home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 2002-12-04 | 544.8 KB | 17,026 lines
use master go dump tran master with no_log go exec dbo.sp_configure 'allow updates',1 go reconfigure with override go set ANSI_NULLS off exec sp_MS_upd_sysobj_category 1 go -------------------------------------------------------------------------------- --. System objects (replsys.sql) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --. sp_MSispulldistributionjobnamegenerated -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSispulldistributionjobnamegenerated') drop procedure sp_MSispulldistributionjobnamegenerated go raiserror('Creating procedure sp_MSispulldistributionjobnamegenerated', 0,1) with nowait go -- -- Name: sp_MSispulldistributionjobnamegenerated -- -- Descriptions: This procedure checks whether a given job id corresponds to -- a pull distribution agent job with a name generated by replication. -- If so, a return value of zero will be returned, otherwise -- a value of one will be returned to the caller. -- -- Notes: 1) For this procedure to be effective, it must match the current -- pull distribution agent name generation algorithm. Note that the -- algorithm used for matching auto-generated job name is not -- exact. (See sp_addpullsubscription_agent replsys.sql) -- 2) This procedure is supposed to be executed at the subscriber -- database. The subscriber server name and subscriber database -- name for contructing the generated job name are obtained via -- the serverproperty('ServerName') and the db_name() functions. -- -- Parameters: @publisher sysname -- @publisher_db sysname -- @publication sysname (This can be null for shared agent) -- @job_id uniqueidentifier -- -- Returns: 0 - If the specified jobid corresponds to a snapshot job with -- a generated name. -- 1 - Otherwise -- -- Security: This is an internal system procedure. -- create procedure dbo.sp_MSispulldistributionjobnamegenerated ( @publisher sysname, @publisher_db sysname, @publication sysname, @job_id uniqueidentifier ) as begin set nocount on declare @generated_job_name nvarchar(4000) declare @generated_job_name_length int declare @job_name sysname select @job_name = null select @job_name = name from msdb.dbo.sysjobs_view where job_id = @job_id if @job_name is null begin goto MISMATCH end -- First of all, make sure that the job is indeed a distribution agent -- job (there should be a step with Distribution as the subsystem in the -- job) if not exists (select * from msdb.dbo.sysjobsteps where job_id = @job_id and upper(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DISTRIBUTION') begin goto MISMATCH end -- Pull distribution agent names are always generated with a guid select @generated_job_name = left(@publisher, 21) + N'-' + left(@publisher_db, 21) + N'-' + left(@publication, 21) + N'-' + left(convert(nvarchar(4000),serverproperty('ServerName')), 21) + N'-' + left(db_name(), 21) + N'-' select @generated_job_name_length = len(@generated_job_name) -- Try matching the prefix of the job name if left(@job_name, @generated_job_name_length) = @generated_job_name begin -- Checks if the tail end of the job name matches a hexadecimal guid -- with embedded dashes if upper(right(@job_name, len(@job_name) - @generated_job_name_length) collate SQL_Latin1_General_CP1_CS_AS) like N'[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]' begin return 0 end else begin goto MISMATCH end end MISMATCH: if @job_name is not null begin raiserror(21695, -1, -1, @job_name) end return 1 end go exec sp_MS_marksystemobject 'dbo.sp_MSispulldistributionjobnamegenerated' -------------------------------------------------------------------------------- --. sp_MSispullmergejobnmaegenerated -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSispullmergejobnamegenerated') drop procedure sp_MSispullmergejobnamegenerated go raiserror('Creating procedure sp_MSispullmergejobnamegenerated', 0,1) with nowait go -- -- Name: sp_MSispullmergejobnamegenerated -- -- Descriptions: This procedure checks whether a given job id corresponds to -- a pull merge agent job with a name generated by replication. -- If so, a return value of zero will be returned, otherwise -- a value of one will be returned to the caller. -- -- Notes: 1) For this procedure to be effective, it must match the current -- pull merge agent name generation algorithm. Note that the -- algorithm used for matching auto-generated job name is not -- exact. (See sp_addmergepullsubscription_agent replsys.sql) -- 2) This procedure is supposed to be executed at the subscriber -- database. The subscriber server name and subscriber database -- name for contructing the generated job name are obtained via -- the serverproperty('ServerName') and the db_name() functions. -- -- Parameters: @publisher sysname -- @publisher_db sysname -- @publication sysname (This can be null for shared agent) -- @job_id uniqueidentifier -- -- Returns: 0 - If the specified jobid corresponds to a snapshot job with -- a generated name. -- 1 - Otherwise -- -- Security: This is an internal system procedure. -- create procedure dbo.sp_MSispullmergejobnamegenerated ( @publisher sysname, @publisher_db sysname, @publication sysname, @job_id uniqueidentifier ) as begin set nocount on declare @generated_job_name nvarchar(4000) declare @generated_job_name_length int declare @job_name sysname select @job_name = null select @job_name = name from msdb.dbo.sysjobs_view where job_id = @job_id if @job_name = null begin goto MISMATCH end -- First of all, make sure that the given job is indeed a merge agent -- job (There should be a step with Distribution as the subsystem in the -- job) if not exists (select * from msdb.dbo.sysjobsteps where job_id = @job_id and upper(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'MERGE') begin goto MISMATCH end -- Pull merge agent names are always generated with a - 0 extension select @generated_job_name = left(@publisher, 23) + N'-' + left(@publisher_db, 23) + N'-' + left(@publication, 23) + N'-' + left(convert(nvarchar(4000),serverproperty('ServerName')), 23) + N'-' + left(db_name(), 23) + N'- 0' if @job_name = @generated_job_name begin return 0 end MISMATCH: if @job_name is not null begin raiserror(21695, -1, -1, @job_name) end return 1 end go exec sp_MS_marksystemobject 'dbo.sp_MSispullmergejobnamegenerated' -------------------------------------------------------------------------------- --. sp_droppullsubscription -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_droppullsubscription') drop procedure sp_droppullsubscription go raiserror('Creating procedure sp_droppullsubscription', 0,1) go CREATE PROCEDURE sp_droppullsubscription ( @publisher sysname, @publisher_db sysname, @publication sysname, /* publication name */ @reserved bit = 0 ) AS SET NOCOUNT ON /* ** Declarations. */ DECLARE @name nvarchar(255) DECLARE @retcode int DECLARE @agent_id binary(16) DECLARE @publisher_ex sysname /* Expression used in the cursor */ DECLARE @publisher_db_ex sysname /* Expression used in the cursor */ DECLARE @publication_ex sysname /* Expression used in the cursor */ DECLARE @expanded bit DECLARE @subscription_type_id int DECLARE @count_sub int DECLARE @drop_null_pub bit DECLARE @drop_push_bit bit DECLARE @push int DECLARE @implicit_transaction int DECLARE @close_cursor_at_commit int DECLARE @owner_sid varbinary(85) DECLARE @owner_name sysname DECLARE @qualified_publication_name nvarchar(512) /* ** Initialization */ SELECT @expanded = 0 SELECT @drop_null_pub = 0 SELECT @push = 0 /* ** Get the original set value off IMPLICIT_TRANSACTIONS and CURSOR_CLOSE_ON_COMMIT ** before set these two to off */ select @implicit_transaction = 0 select @close_cursor_at_commit = 0 IF (@reserved = 0) BEGIN SELECT @implicit_transaction = @@options & 2 SELECT @close_cursor_at_commit = @@options & 4 SET IMPLICIT_TRANSACTIONS OFF SET CURSOR_CLOSE_ON_COMMIT OFF END /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_subscribe IF @@ERROR <> 0 or @retcode <> 0 RETURN(1) SELECT @drop_push_bit = 0 /* ** Check parameter and set expressions used by cursor */ /* Publisher */ IF @publisher IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher') RETURN (1) END IF @publisher = 'all' BEGIN SELECT @publisher_ex = '%' SELECT @expanded = 1 END ELSE BEGIN EXECUTE @retcode = dbo.sp_validname @publisher IF @retcode <> 0 RETURN (1) SELECT @publisher_ex = @publisher END /* Publisher_db */ IF @publisher_db IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher_db') RETURN (1) END IF @publisher_db = 'all' BEGIN SELECT @publisher_db_ex = '%' select @expanded = 1 END ELSE BEGIN /* EXECUTE @retcode = dbo.sp_validname @publisher_db IF @retcode <> 0 RETURN (1) */ SELECT @publisher_db_ex = @publisher_db END /* ** Publication ** '' is not a valid name but it may be in the publication name in the table. */ IF @publication IS NULL OR @publication = '' BEGIN SELECT @drop_null_pub = 1 END ELSE IF @publication = 'all' BEGIN SELECT @publication_ex = '%' SELECT @expanded = 1 SELECT @drop_null_pub = 1 END ELSE BEGIN EXECUTE @retcode = dbo.sp_validname @publication IF @retcode <> 0 RETURN (1) SELECT @publication_ex = @publication END /* ** Check to see if the subscription table exists */ IF NOT EXISTS (SELECT * FROM sysobjects WHERE type = 'U' AND name = 'MSreplication_subscriptions') BEGIN IF @expanded = 0 BEGIN RAISERROR(14135, 11, -1, @publisher, @publisher_db, @publication) RETURN(1) END ELSE RETURN(0) END IF @expanded = 0 BEGIN /* ** ** Check to see if the subscription entry exists */ IF NOT EXISTS (SELECT * FROM MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher) AND publisher_db = @publisher_db AND publication = @publication) BEGIN RAISERROR(14135, 11, -1, @publisher, @publisher_db, @publication) RETURN(1) END /* ** Make sure the subscription is not push type if @drop_push_bit = 0 */ IF @drop_push_bit = 0 BEGIN IF EXISTS (SELECT * FROM MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher) AND publisher_db = @publisher_db AND publication = @publication AND subscription_type = @push AND @drop_push_bit = 0) BEGIN RAISERROR(20017, 16, -1) RETURN(1) END END END ELSE /* ** Open a cursor and call recursively if ** parameters are expanded. */ BEGIN /* ** Note: Any expression check on null value is false ** @subscription_type_id is NULL <==> push ** @subscription_type_id is NOT NULL <==> non push */ -- Have to use static cursor option because DECLARE hCdroppullsubscription CURSOR STATIC LOCAL FORWARD_ONLY FOR SELECT DISTINCT publisher, publisher_db, publication FROM MSreplication_subscriptions WHERE ((@publisher_ex = N'%') OR (UPPER(publisher) = UPPER(@publisher_ex))) AND ((@publisher_db_ex = N'%') OR ( publisher_db = @publisher_db_ex)) AND (publication LIKE @publication_ex OR (@drop_null_pub = 1 AND publication IS NULL)) AND ((@drop_push_bit =0 AND subscription_type <> @push) OR @drop_push_bit = 1) FOR READ ONLY OPEN hCdroppullsubscription FETCH hCdroppullsubscription INTO @publisher, @publisher_db, @publication WHILE (@@fetch_status <> -1) BEGIN EXECUTE @retcode = dbo.sp_droppullsubscription @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @reserved = 1 FETCH hCdroppullsubscription INTO @publisher, @publisher_db, @publication END CLOSE hCdroppullsubscription DEALLOCATE hCdroppullsubscription RETURN (0) END /* ** Only members of the sysadmin group and the creator of the distribution ** agent can drop a pull subscription successfully. This behavior matches ** the behavior of the sysjobs_view. DBO of the subscriber database, ** sysadmins (owner is undefined) can drop a subscription if the owner_sid ** is null. */ EXEC sp_MSget_pullsubsagent_owner @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @owner_sid = @owner_sid OUTPUT IF (@owner_sid is not null AND (SUSER_SID() <> @owner_sid) AND (ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) = 0)) BEGIN SELECT @owner_name = SUSER_SNAME(@owner_sid) SELECT @qualified_publication_name = @publisher + N':' + @publisher_db + N':' + @publication RAISERROR(21121,16,-1,@owner_name, @qualified_publication_name) RETURN (1) END /* ** Get the agent name, it may be dropped later. */ SELECT @agent_id = agent_id FROM MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher) AND publisher_db = @publisher_db AND publication = @publication -- If the agent is used by other subscription, don't drop it. if (select count(*) from MSreplication_subscriptions where agent_id = @agent_id) > 1 select @agent_id = NULL begin tran save TRAN droppullsubscription /* ** Drop the subscription entry and the distribution agent if it exists */ /* ** If the distribution agent is not used anymore, ** drop the agent if it exists */ IF @agent_id IS NOT NULL BEGIN IF (EXISTS (SELECT * FROM msdb..sysjobs_view WHERE job_id = @agent_id)) BEGIN -- Checks if the job name matches one that is generated -- by replication EXEC @retcode = dbo.sp_MSispulldistributionjobnamegenerated @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @job_id = @agent_id IF @@ERROR <> 0 GOTO UNDO -- Only drop jobs if the name was generated IF @retcode = 0 BEGIN EXEC @retcode = msdb.dbo.sp_delete_job @job_id = @agent_id IF @@ERROR <> 0 or @retcode <> 0 GOTO UNDO -- Delete MSreplication_subsciptions table after dropping -- the distribution agent and delay one second -- to avoid deadlock with it. WAITFOR DELAY '00:00:01' END END END /* Call sp_MSunregistersubscription so that the reg entries get deleted */ declare @subscriber_db sysname set @subscriber_db = DB_NAME() exec @retcode = dbo.sp_MSunregistersubscription @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @subscriber = @@SERVERNAME, @subscriber_db = @subscriber_db IF @retcode<>0 or @@ERROR<>0 GOTO UNDO /* -- Delete MSreplication_subsciptions table after dropping the distribution agent\ -- To avoid deadlock with it. --DELETE MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher) AND --publisher_db = @publisher_db AND --publication = @publication --IF @@ERROR <> 0 -- GOTO UNDO */ IF EXISTS(select * from sysobjects where type='U' and name = 'MSsubscription_properties') BEGIN DELETE FROM MSsubscription_properties WHERE UPPER(publisher) = UPPER(@publisher) AND publisher_db = @publisher_db AND publication = @publication IF @@ERROR <> 0 GOTO UNDO IF NOT EXISTS (SELECT * FROM MSsubscription_properties) BEGIN exec @retcode = dbo.sp_MSsub_cleanup_prop_table IF @@ERROR <> 0 or @retcode <> 0 GOTO UNDO END END /* ** Clean up metadata at subscriber side */ -- Note: sp_subscription_cleanup should be called after deleting the row -- in MSreplication_subscriptions. exec @retcode = dbo.sp_subscription_cleanup @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication IF @retcode<>0 or @@ERROR<>0 GOTO UNDO -- -- drop table MSreplication_subscriptions if empty and -- not in recursive call -- IF EXISTS (SELECT * FROM sysobjects WHERE name = 'MSreplication_subscriptions' AND type = 'U') BEGIN IF (@reserved = 0 AND NOT EXISTS (SELECT * FROM MSreplication_subscriptions)) BEGIN DROP TABLE MSreplication_subscriptions IF @@ERROR <> 0 GOTO UNDO END END COMMIT TRAN /* ** set back the two settings if needed */ if @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END RETURN (0) UNDO: IF @@TRANCOUNT > 0 begin ROLLBACK TRAN droppullsubscription COMMIT TRAN end /* ** set back the two settings if needed */ if @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END return 1 go exec sp_MS_marksystemobject 'dbo.sp_droppullsubscription' grant execute on dbo.sp_droppullsubscription to public -------------------------------------------------------------------------------- --. sp_dropmergepullsubscription -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_dropmergepullsubscription') drop procedure sp_dropmergepullsubscription go raiserror('Creating procedure sp_dropmergepullsubscription', 0,1) GO CREATE PROCEDURE sp_dropmergepullsubscription( @publication sysname = NULL, /* Publication name */ @publisher sysname = NULL, /* Publisher server */ @publisher_db sysname = NULL, /* Publication database */ @reserved bit = 0 )AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int declare @subscriber_srvid int declare @publisher_srvid int declare @pubid uniqueidentifier declare @subid uniqueidentifier declare @partnerid uniqueidentifier declare @local_server sysname declare @local_db sysname declare @merge_jobid binary(16) declare @cmd nvarchar(255) declare @pubidstr nvarchar(38) declare @subscriber sysname declare @subscriber_db sysname declare @subscriber_type int declare @local_job bit declare @implicit_transaction int declare @close_cursor_at_commit int declare @owner_sid varbinary(85) declare @owner_name sysname declare @qualified_publication_name nvarchar(512) select @close_cursor_at_commit = 0 select @implicit_transaction = 0 /* ** Get original setting values before setting them to false for recursive calling */ IF (@reserved = 0) BEGIN SELECT @implicit_transaction = @@options & 2 SELECT @close_cursor_at_commit = @@options & 4 SET IMPLICIT_TRANSACTIONS OFF SET CURSOR_CLOSE_ON_COMMIT OFF END /* ** Security Check. */ exec @retcode = dbo.sp_MSreplcheck_subscribe if @@ERROR <> 0 or @retcode <> 0 return(1) /* ** Initializations. */ set @local_db = DB_NAME() set @local_server = @@SERVERNAME set @subscriber = @@SERVERNAME set @subscriber_db = DB_NAME() /* ** Assign parameter values appropriately */ select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default IF @subscriber_srvid IS NULL BEGIN RAISERROR (14010, 16, -1) RETURN (1) END IF not exists (select name from sysobjects where name='sysmergesubscriptions') BEGIN RAISERROR (14055, 16, -1) RETURN (1) END /* ** Parameter Check: @publisher ** Check to make sure that the publisher is defined */ IF @publisher IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher') RETURN (1) END EXECUTE @retcode = dbo.sp_validname @publisher IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) /* ** Parameter Check: @publisher_db */ IF @publisher_db IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher_db') RETURN (1) END /* ** Parameter Check: @publication. ** If the publication name is specified, check to make sure that it ** conforms to the rules for identifiers and that the publication ** actually exists. Disallow NULL. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END IF LOWER(@publication) = 'all' BEGIN declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergepublications FOR READ ONLY OPEN hC1 FETCH hC1 INTO @publication if @@fetch_status = -1 begin CLOSE hC1 DEALLOCATE hC1 RETURN (0) --- It's OK to have no publication when 'ALL' end WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergepullsubscription @publication = @publication, @publisher = @publisher, @publisher_db = @publisher_db, @reserved = 1 FETCH hC1 INTO @publication END CLOSE hC1 DEALLOCATE hC1 RETURN (0) END IF LOWER(@publisher) = 'all' BEGIN declare hC4 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT srvname FROM master..sysservers FOR READ ONLY OPEN hC4 FETCH hC4 INTO @publisher WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergepullsubscription @publication = @publication, @publisher = @publisher, @publisher_db = @publisher_db, @reserved = 1 FETCH hC4 INTO @publisher END CLOSE hC4 DEALLOCATE hC4 RETURN (0) END /* ** Validate that the publisher is a valid server */ select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default IF @publisher_srvid IS NULL BEGIN --RAISERROR (14010, 16, -1) RETURN (1) END /* Previously the condition is set as 'AND subid<>pubid' which is fatally errorous */ IF LOWER(@publisher_db) = 'all' BEGIN declare hC5 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT db_name FROM sysmergesubscriptions WHERE subid = pubid and pubid in (select pubid from sysmergepublications where UPPER(publisher)=UPPER(@publisher) and name=@publication) FOR READ ONLY OPEN hC5 FETCH hC5 INTO @publisher_db WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergepullsubscription @publication = @publication, @publisher = @publisher, @publisher_db = @publisher_db, @reserved = 1 FETCH hC5 INTO @publisher_db END CLOSE hC5 DEALLOCATE hC5 RETURN (0) END /* ** return error if only there is no 'ALL'. Same is true for the rest of error handling. */ if NOT EXISTS (select * FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db) BEGIN if @reserved = 0 RAISERROR (20026, 16, -1, @publication) RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' if @pubid is null BEGIN if @reserved = 0 RAISERROR (20026, 16, -1, @publication) RETURN (1) END /* ** Only members of the sysadmin group and the creator of the distribution ** agent can drop a pull subscription successfully. This behavior matches ** the behavior of the sysjobs_view. DBO of the subscriber database, ** sysadmins (owner is undefined) can drop a subscription if the owner_sid ** is null. */ EXEC sp_MSget_mergepullsubsagent_owner @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @owner_sid = @owner_sid OUTPUT IF (@owner_sid is not null AND (SUSER_SID() <> @owner_sid) AND (ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) = 0)) BEGIN SELECT @owner_name = SUSER_SNAME(@owner_sid) SELECT @qualified_publication_name = @publisher + N':' + @publisher_db + N':' + @publication RAISERROR(21121,16,-1,@owner_name, @qualified_publication_name) RETURN (1) END /* ** Get subscriptions from either local replicas or global replicas */ select @subid = subs1.subid, @subscriber_type = subs1.subscriber_type, @partnerid = subs2.subid from sysmergesubscriptions subs1, sysmergesubscriptions subs2, sysmergepublications pubs where subs1.srvid = @subscriber_srvid and subs1.db_name = @subscriber_db and subs2.srvid = @publisher_srvid and subs2.db_name = @publisher_db and subs1.pubid = subs2.subid and subs2.pubid = pubs.pubid and pubs.name = @publication and UPPER(pubs.publisher)=UPPER(@publisher) and pubs.publisher_db=@publisher_db if @subid IS NULL begin if @reserved = 0 raiserror (14050, 16, -1) RETURN (0) end begin tran save TRAN dropmergepullsubscription /* ** Drop the local merge task */ select @merge_jobid = merge_jobid from MSmerge_replinfo WHERE repid = @subid if (@merge_jobid IS NOT NULL) BEGIN IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE job_id = @merge_jobid) BEGIN -- Checks if the job name matches one that is generated -- by replication EXEC @retcode = dbo.sp_MSispullmergejobnamegenerated @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @job_id = @merge_jobid IF @@ERROR <> 0 GOTO FAILURE -- Only drop the job if the name was generated IF @retcode = 0 BEGIN EXEC @retcode = msdb.dbo.sp_delete_job @job_id = @merge_jobid IF @@ERROR <> 0 or @retcode <> 0 GOTO FAILURE END END END if @subid <> @partnerid BEGIN DELETE MSmerge_replinfo WHERE repid = @subid IF @@ERROR <> 0 GOTO FAILURE delete from sysmergesubscriptions where subid = @subid if @@ERROR <> 0 GOTO FAILURE /* Call sp_MSunregistersubscription so that the reg entries get deleted */ exec @retcode = dbo.sp_MSunregistersubscription @publisher = @publisher, @publisher_db = @publisher_db, @publication = @publication, @subscriber = @@SERVERNAME, @subscriber_db = @subscriber_db IF @retcode<>0 or @@ERROR<>0 GOTO FAILURE exec dbo.sp_MSpublicationcleanup @publisher=@publisher, @publisher_db = @publisher_db, @publication = @publication IF @@ERROR <> 0 BEGIN RAISERROR (20025, 16, -1, @publication) GOTO FAILURE END END IF EXISTS(select * from sysobjects where type='U' and name = 'MSsubscription_properties') BEGIN DELETE FROM MSsubscription_properties WHERE UPPER(publisher) = UPPER(@publisher) AND publisher_db = @publisher_db AND publication = @publication IF @@ERROR <> 0 GOTO FAILURE IF NOT EXISTS (SELECT * FROM MSsubscription_properties) BEGIN exec @retcode = dbo.sp_MSsub_cleanup_prop_table IF @@ERROR <> 0 or @retcode <> 0 GOTO FAILURE END END COMMIT TRAN /* ** Set back original settings */ IF @reserved = 0 BEGIN /* ** If last subscription is dropped and the DB is not enabled for publishing, ** then remove the merge system tables */ IF (not exists (select * from sysmergesubscriptions )) AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME())=0 BEGIN execute @retcode = dbo.sp_MSdrop_mergesystables if @@ERROR <> 0 or @retcode <> 0 begin return (1) end END IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END RETURN(0) FAILURE: RAISERROR (14056, 16, -1) if @@trancount > 0 begin ROLLBACK TRANSACTION dropmergepullsubscription COMMIT TRANSACTION end /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END return 1 go exec sp_MS_marksystemobject 'dbo.sp_dropmergepullsubscription' grant execute on dbo.sp_dropmergepullsubscription to public -------------------------------------------------------------------------------- --. sp_MSenum_replsqlqueues -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenum_replsqlqueues') drop procedure sp_MSenum_replsqlqueues go raiserror('Creating procedure sp_MSenum_replsqlqueues', 0,1) go create procedure sp_MSenum_replsqlqueues ( @curdistdb sysname = NULL ) as begin declare @distbit int declare @db_name sysname declare @cmd nvarchar(1024) select @distbit = 16 -- -- security check -- if (is_srvrolemember('sysadmin') != 1) begin -- -- non SA user -- @curdistdb cannot be null for NON-SA user -- if (@curdistdb is null) begin raiserror (14043, 16, -1, '@curdistdb') return 1 end else begin -- -- The user has to be DBO of the specified distribution db -- declare @fisdbo bit ,@securitycmd nvarchar(300) select @securitycmd = quotename(@curdistdb) + '.dbo.sp_executesql' exec @securitycmd N'if is_member(N''db_owner'') = 1 set @fisdbo = 1' ,N'@fisdbo bit output' ,@fisdbo output if (@fisdbo != 1) begin raiserror (21050, 14, 3) return 1 end end end -- -- create the temp table to store the relevant information -- create table #replqueue ( publisher sysname collate database_default not null, publisher_db sysname collate database_default not null, subscriber sysname collate database_default not null, subscriber_db sysname collate database_default not null, publication sysname collate database_default not null, dist_db sysname collate database_default not null ) create unique index ucreplqueue ON #replqueue (subscriber, subscriber_db, publication) -- -- Has the user specified a distribution database -- if (@curdistdb is NULL) begin -- -- Go through all the distribution databases -- declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR select name from master.dbo.sysdatabases where category & @distbit <> 0 and has_dbaccess(name) = 1 for read only end else begin -- -- User specified Distribution Database -- Validate the user specified name -- if exists (select name from master.dbo.sysdatabases where name = @curdistdb and category & @distbit <> 0 and has_dbaccess(name) = 1) begin declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR select @curdistdb for read only end else begin -- -- Error : Invalid distribution db specified -- raiserror(20587, 16, 3, N'@curdistdb', N'sp_MSenum_replsqlqueues') return 1 end end -- -- Enumerate -- open hCdatabase fetch next from hCdatabase into @db_name while (@@fetch_status <> -1) begin select @cmd = 'SET NOCOUNT ON ' + 'INSERT INTO #replqueue (publisher, publisher_db, subscriber, subscriber_db, publication, dist_db) ' + 'SELECT c.srvname, a.publisher_db, b.srvname, a.subscriber_db, a.publication, N''' + @db_name + ''' ' + 'FROM ' + QUOTENAME(@db_name) + '.dbo.MSdistribution_agents as a ' + 'JOIN master.dbo.sysservers as b ' + 'ON a.subscriber_id = b.srvid ' + 'JOIN master.dbo.sysservers as c ' + 'ON a.publisher_id = c.srvid ' + 'WHERE queue_id = N''mssqlqueue'' ' exec (@cmd) fetch next from hCdatabase into @db_name end close hCdatabase deallocate hCdatabase -- -- select the contents of the temp table -- select * from #replqueue -- -- cleanup -- drop table #replqueue end go EXEC dbo.sp_MS_marksystemobject sp_MSenum_replsqlqueues go grant execute on dbo.sp_MSenum_replsqlqueues to public go -------------------------------------------------------------------------------- --. sp_MSenum_replqueues -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenum_replqueues') drop procedure sp_MSenum_replqueues go raiserror('Creating procedure sp_MSenum_replqueues', 0,1) go create procedure sp_MSenum_replqueues ( @curdistdb sysname = NULL ) as begin declare @distbit int declare @db_name sysname declare @cmd nvarchar(1024) select @distbit = 16 -- -- security check -- if (is_srvrolemember('sysadmin') != 1) begin -- -- non SA user -- @curdistdb cannot be null for NON-SA user -- if (@curdistdb is null) begin raiserror (14043, 16, -1, '@curdistdb') return 1 end else begin -- -- The user has to be DBO of the specified distribution db -- declare @fisdbo bit ,@securitycmd nvarchar(300) select @securitycmd = quotename(@curdistdb) + '.dbo.sp_executesql' exec @securitycmd N'if is_member(N''db_owner'') = 1 set @fisdbo = 1' ,N'@fisdbo bit output' ,@fisdbo output if (@fisdbo != 1) begin raiserror (21050, 14, 3) return 1 end end end -- -- create the temp table to store the relevant information -- create table #replqueue ( queue_server sysname collate database_default not null, queue_id sysname collate database_default not null, dist_db sysname collate database_default not null ) create unique clustered index ucreplqueue ON #replqueue (queue_id) -- -- Has the user specified a distribution database -- if (@curdistdb is NULL) begin -- -- Go through all the distribution databases -- declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR select name from master.dbo.sysdatabases where category & @distbit <> 0 and has_dbaccess(name) = 1 for read only end else begin -- -- User specified Distribution Database -- Validate the user specified name -- if exists (select name from master.dbo.sysdatabases where name = @curdistdb and category & @distbit <> 0 and has_dbaccess(name) = 1) begin declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR select @curdistdb for read only end else begin -- -- Error : Invalid distribution db specified -- raiserror(20587, 16, 4, N'@curdistdb', N'sp_MSenum_replqueues') return 1 end end -- -- Enumerate -- open hCdatabase fetch next from hCdatabase into @db_name while (@@fetch_status <> -1) begin select @cmd = 'SET NOCOUNT ON ' + 'INSERT INTO #replqueue (queue_server, queue_id, dist_db) ' + 'SELECT queue_server, queue_id, ' + 'N''' + replace(@db_name, '''', '''''') + ''' ' + 'FROM ' + QUOTENAME(@db_name) + '.dbo.MSdistribution_agents ' + 'WHERE ' + 'queue_id IS NOT NULL and queue_id != N''mssqlqueue''' exec (@cmd) fetch next from hCdatabase into @db_name end close hCdatabase deallocate hCdatabase -- -- select the contents of the temp table to present -- the formatted queue name -- select N'DIRECT=OS:' + queue_server + N'\PRIVATE$\' + queue_id AS 'queue_format' ,dist_db from #replqueue -- -- cleanup -- drop table #replqueue end go EXEC dbo.sp_MS_marksystemobject sp_MSenum_replqueues go grant execute on dbo.sp_MSenum_replqueues to public go -------------------------------------------------------------------------------- --. sp_vupgrade_publisherdb -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_vupgrade_publisherdb') drop procedure sp_vupgrade_publisherdb go raiserror('Creating procedure sp_vupgrade_publisherdb', 0,1) go create procedure sp_vupgrade_publisherdb @ver_old int, @ver_retention int as begin /* * Process schema and metadata changes specific to a publishing database. Transactional replication * system tables at the publisher are updated by sp_vupgrade_publisherdb; merge tables are not. * Most merge system tables exist in both the publishing and subscribing databases; merge schema * and metadata changes are processed by a separate pass over all databases in sp_vupgrade_mergetables. * * Match column order of newly created table when adding columns. * * Setup version upgrade procedure call order: * sp_vupgrade_replication -> sp_vupgrade_publisher -> sp_vupgrade_publisherdb */ set nocount on declare @default_name sysname -- raiserror('sp_vupgrade_publisherdb', 0,1) with nowait -- sysarticles if exists( select name from sysobjects where name = 'sysarticles' ) begin if exists( select * from syscolumns where id = object_id('dbo.sysarticles') and name = 'schema_option' ) begin -- The following two-phase upgrade operation has to be atomic begin transaction save transaction sysarticles_upgrade -- For table articles which used to have the -- SQLDMOCreationScript_DRI_Primary (0x00000080) schema option enabled, -- turn on the SQLDMOCreationScript_PKFKAsConstraints (0x00008000) -- option update sysarticles set schema_option = convert(int, schema_option) | convert(int, 0x00008000) from sysobjects so where (convert(int, schema_option) & 0x00000080) <> 0x00000000 and so.id = sysarticles.objid and so.xtype = 'U' if @@error <> 0 goto SYSARTICLE_ERROR -- Enable both the SQLDMOCreationScript_DRI_PrimaryKey and -- SQLDMOCreationScript_UniqueKeys options (0x00004000) if at least -- one of SQLDMOCreationScript_NonClusteredIndexes (0x00000010) and -- SQLDMOCreationScript_ClusteredIndexes (0x00000040) was enabled -- or the table article belongs to a transactional publication update sysarticles set schema_option = convert(int, schema_option) | convert(int, 0x00004080) from sysobjects so, syspublications sp where ((sysarticles.pubid = sp.pubid and sp.repl_freq = 0) or (convert(int, schema_option) & convert(int, 0x00000050) <> 0x00000000)) and so.id = sysarticles.objid and so.xtype = 'U' if @@error <> 0 goto SYSARTICLE_ERROR -- Skip over the error handling code goto SYSARTICLE_END SYSARTICLE_ERROR: rollback transaction sysarticles_upgrade commit transaction return 1 SYSARTICLE_END: commit transaction end end -- end of sysarticles upgrade -- syssubscriptions if exists (select name from sysobjects where name='syssubscriptions') begin if not exists (select * from syscolumns where id = object_id('syssubscriptions') and name = 'queued_reinit') begin alter table syssubscriptions add queued_reinit bit default 0 not null end end -- end of syssubscriptions upgrade -- syspublications if exists (select name from sysobjects where name='syspublications') begin -- default_access column no longer used if exists (select * from syscolumns where id = object_id('syspublications') and name = 'default_access') begin alter table syspublications drop column default_access end /* * Queued updating subscriptions option; conflict management settings added later in this proc */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'allow_queued_tran') begin alter table syspublications add allow_queued_tran bit default 0 not null end /* * Portable snapshot */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'snapshot_in_defaultfolder') begin alter table syspublications add snapshot_in_defaultfolder bit default 1 not null end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'alt_snapshot_folder') begin alter table syspublications add alt_snapshot_folder nvarchar(255) null end /* * Snapshot pre/post commands */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'pre_snapshot_script') begin alter table syspublications add pre_snapshot_script nvarchar(255) null end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'post_snapshot_script') begin alter table syspublications add post_snapshot_script nvarchar(255) null end /* * Snapshot compression */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'compress_snapshot') begin alter table syspublications add compress_snapshot bit default 0 not null end /* * Post SQL7.0 FTP configuration stored at publisher */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_address') begin alter table syspublications add ftp_address sysname null end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_port') begin alter table syspublications add ftp_port int not null default 21 end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_subdirectory') begin alter table syspublications add ftp_subdirectory nvarchar(255) null end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_login') begin alter table syspublications add ftp_login sysname null default N'anonymous' end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_password') begin alter table syspublications add ftp_password nvarchar(524) null end -- Since the ftp_address is now required to enable a publication for -- internet, publications that were enabled for internet can not -- be upgraded automatically. So the enabled for internet option -- is reset in the upgrade process. if exists (select * from syscolumns where id = object_id('syspublications') and name = 'enabled_for_internet') begin update dbo.syspublications set enabled_for_internet = 0 end /* * Transformable subscriptions */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'allow_dts') begin alter table syspublications add allow_dts bit default 0 not null end /* * Attach & Go */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'allow_subscription_copy') begin alter table syspublications add allow_subscription_copy bit default 0 not null end /* * Transactional conflict management */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'centralized_conflicts') begin alter table syspublications add centralized_conflicts bit NULL end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'conflict_retention') begin alter table syspublications add conflict_retention int NULL end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'conflict_policy') begin alter table syspublications add conflict_policy int NULL end /* * Attach & Go */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'queue_type') begin alter table syspublications add queue_type int NULL end /* * Active Directory */ if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ad_guidname') begin alter table syspublications add ad_guidname sysname null end if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'backward_comp_level') begin alter table syspublications add backward_comp_level int default 10 not null end /* * Schema only articles (views, procs, udfs) */ if not exists (select * from sysobjects where name = 'sysschemaarticles') begin create table dbo.sysschemaarticles ( artid int NOT NULL, creation_script nvarchar(255) NULL, description nvarchar(255) NULL, dest_object sysname NOT NULL, name sysname NOT NULL, objid int NOT NULL, pubid int NOT NULL, pre_creation_cmd tinyint NOT NULL, status int NOT NULL, type tinyint NOT NULL, schema_option binary(8) NULL, dest_owner sysname NULL ) exec dbo.sp_MS_marksystemobject sysschemaarticles if not exists (select * from sysindexes where name = 'unc1sysschemaarticles') begin create unique nonclustered index unc1sysschemaarticles on sysschemaarticles(artid, pubid) end end if exists (select * from sysobjects where name = 'sysextendedarticlesview') begin drop view dbo.sysextendedarticlesview end -- cannot create view directly in stored procedure exec ( 'create view dbo.sysextendedarticlesview as select artid, columns, creation_script, del_cmd, description, dest_table, filter, filter_clause, ins_cmd, name, objid, pubid, pre_creation_cmd, status, sync_objid, type, upd_cmd, schema_option, dest_owner from sysarticles union all select artid, NULL, creation_script, NULL, description, dest_object, NULL, NULL, NULL, name, objid, pubid, pre_creation_cmd, status, NULL, type, NULL, schema_option, dest_owner from sysschemaarticles' ) exec dbo.sp_MS_marksystemobject 'sysextendedarticlesview' exec sp_vupgrade_syscol_status end -- sysarticleupdates if exists (select name from sysobjects where name='sysarticleupdates') begin if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and name = 'sync_upd_trig') begin alter table sysarticleupdates add sync_upd_trig int default 0 NOT NULL end if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and name = 'conflict_tableid') begin alter table sysarticleupdates add conflict_tableid int NULL end if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and name = 'ins_conflict_proc') begin alter table sysarticleupdates add ins_conflict_proc int NULL end if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and name = 'identity_support') begin alter table sysarticleupdates add identity_support bit default 0 NOT NULL end end -- Upgrade dbt->distbackuplsn -- Make sure the upgrade is done for 8.0 Beta 2 customers. if exists (select * from sysobjects where name = 'sysarticles') and not exists (select * from sysobjects where name = 'systranschemas') begin -- Force to get in even if the logreader is running. exec sp_replflush exec sp_repldone @xactid = NULL, @xact_segno = NULL, @numtrans = 0, @time = 0, @reset = 0, @code = 1 -- Unmark the connection as the logreader. exec sp_replflush end -- Create new tran tables if the db is enabled for tran publishing. if exists (select name from sysobjects where name='syspublications') begin exec dbo.sp_MScreate_pub_tables end /* * syspublications */ if exists (select name from sysobjects where name='syspublications') begin if not exists (select * from syscolumns where id = Object_Id('syspublications') and name = 'ftp_password' and length = '1048') begin /* * syspublications ftp_password * no need to upgrade passwords since this column is new in 8.0. */ declare @dbname sysname declare @cmptlevel tinyint set @dbname = db_name() select @cmptlevel = cmptlevel from master..sysdatabases where name = @dbname collate database_default if @cmptlevel < 70 begin raiserror (15048, -1, -1, 70, 70, 70, 80) end else begin exec( 'alter table syspublications alter column ftp_password nvarchar(524)' ) end end -- change non-clustered index on syspublications.pubid to clustered -- index if exists( select * from sysindexes where name = 'unc1syspublications' and id = object_id('dbo.syspublications') ) begin drop index dbo.syspublications.unc1syspublications end if not exists ( select * from sysindexes where name = 'uc1syspublications' and id = object_id('dbo.syspublications') ) begin create unique clustered index uc1syspublications on syspublications (pubid) end end end go exec dbo.sp_MS_marksystemobject sp_vupgrade_publisherdb go -------------------------------------------------------------------------------- --. sp_MSreset_queue -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSreset_queue') revoke execute on dbo.sp_MSreset_queue from public -------------------------------------------------------------------------------- --. sp_MSscript_begintrig1 -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_begintrig1') revoke execute on dbo.sp_MSscript_begintrig1 from public -------------------------------------------------------------------------------- --. sp_MSscript_begintrig2 -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_begintrig2') revoke execute on dbo.sp_MSscript_begintrig2 from public -------------------------------------------------------------------------------- --. sp_MSscript_endtrig -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_endtrig') revoke execute on dbo.sp_MSscript_endtrig from public -------------------------------------------------------------------------------- --. sp_MSscript_multirow_trigger -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_multirow_trigger') revoke execute on dbo.sp_MSscript_multirow_trigger from public -------------------------------------------------------------------------------- --. sp_MSscript_params -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_params') revoke execute on dbo.sp_MSscript_params from public -------------------------------------------------------------------------------- --. sp_MSscript_pkvar_assignment -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_pkvar_assignment') revoke execute on dbo.sp_MSscript_pkvar_assignment from public -------------------------------------------------------------------------------- --. sp_MSscript_procbodystart -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_procbodystart') revoke execute on dbo.sp_MSscript_procbodystart from public -------------------------------------------------------------------------------- --. sp_MSscript_singlerow_trigger -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_singlerow_trigger') revoke execute on dbo.sp_MSscript_singlerow_trigger from public -------------------------------------------------------------------------------- --. sp_MSscript_trigger_assignment -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_trigger_assignment') revoke execute on dbo.sp_MSscript_trigger_assignment from public -------------------------------------------------------------------------------- --. sp_MSscript_trigger_exec_rpc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_trigger_exec_rpc') revoke execute on dbo.sp_MSscript_trigger_exec_rpc from public -------------------------------------------------------------------------------- --. sp_MSscript_trigger_fetch_statement -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_trigger_fetch_statement') revoke execute on dbo.sp_MSscript_trigger_fetch_statement from public -------------------------------------------------------------------------------- --. sp_MSscript_trigger_update_checks -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_trigger_update_checks') revoke execute on dbo.sp_MSscript_trigger_update_checks from public -------------------------------------------------------------------------------- --. sp_MSscript_trigger_updates -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_trigger_updates') revoke execute on dbo.sp_MSscript_trigger_updates from public -------------------------------------------------------------------------------- --. sp_MSclearcolumnbit -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSclearcolumnbit') revoke execute on dbo.sp_MSclearcolumnbit from public -------------------------------------------------------------------------------- --. sp_MSget_subtypedatasrc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSget_subtypedatasrc') revoke execute on dbo.sp_MSget_subtypedatasrc from public -------------------------------------------------------------------------------- --. sp_MSCheckmergereplication -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSCheckmergereplication') revoke execute on dbo.sp_MSCheckmergereplication from public -------------------------------------------------------------------------------- --. sp_MSremove_userscript -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSremove_userscript') revoke execute on dbo.sp_MSremove_userscript from public -------------------------------------------------------------------------------- --. sp_MSscript_trigger_variables -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_trigger_variables') revoke execute on dbo.sp_MSscript_trigger_variables from public -------------------------------------------------------------------------------- --. sp_MSscript_where_clause -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_where_clause') revoke execute on dbo.sp_MSscript_where_clause from public -------------------------------------------------------------------------------- --. sp_MSupdate_mqserver_subdb -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSupdate_mqserver_subdb') revoke exec on dbo.sp_MSupdate_mqserver_subdb from public go -------------------------------------------------------------------------------- --. sp_MSscript_sync_del_trig -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_sync_del_trig') drop procedure sp_MSscript_sync_del_trig go create procedure sp_MSscript_sync_del_trig ( @objid int, @publisher sysname, @publisher_db sysname, @publication sysname, @trigname sysname, @procname sysname, @proc_owner sysname, @cftproc sysname, @agent_id int, @identity_col sysname = NULL, @ts_col sysname = NULL, @filter_clause nvarchar(4000), @primary_key_bitmap varbinary(4000) ) as BEGIN declare @colname sysname ,@cmd nvarchar(4000) ,@ins_cmd nvarchar(4000) ,@columns binary(32) ,@outvars nvarchar(4000) ,@rc int ,@qualname nvarchar(512) ,@fisqueued bit set nocount on -- -- security check -- exec @rc = sp_MSreplcheck_subscribe if @@error <> 0 or @rc <> 0 begin return (1) end exec sp_MSget_qualified_name @objid, @qualname OUTPUT if (LOWER(@cftproc) = N'null') begin select @fisqueued = 0 ,@cftproc = NULL end else select @fisqueued = 1 if @ts_col in ('null','NULL') select @ts_col = null if @identity_col in ('null','NULL') select @identity_col = null -- Create temp table create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- 1st preamble common to all synctran procs exec dbo.sp_MSscript_begintrig1 @trigname, @objid, @procname, @filter_clause, 'del', @fisqueued -- 2nd preamble common to all synctran procs exec dbo.sp_MSscript_begintrig2 @publisher, @publisher_db, @publication, @objid, 'del', @agent_id, @fisqueued -- script single row handling exec @rc = dbo.sp_MSscript_singlerow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, @cftproc, @identity_col, @ts_col, 'del', @primary_key_bitmap -- script multi-row handling exec @rc = dbo.sp_MSscript_multirow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, @cftproc, @identity_col, @ts_col, 'del', @primary_key_bitmap -- script end of trigger exec dbo.sp_MSscript_endtrig -- send fragments to client select procedure_text from #proctext order by c1 asc END go exec dbo.sp_MS_marksystemobject sp_MSscript_sync_del_trig go grant execute on dbo.sp_MSscript_sync_del_trig to public go -------------------------------------------------------------------------------- --. sp_MSscript_sync_ins_trig -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_sync_ins_trig') drop procedure sp_MSscript_sync_ins_trig go raiserror('Creating procedure sp_MSscript_sync_ins_trig', 0,1) go create procedure sp_MSscript_sync_ins_trig ( @objid int, @publisher sysname, @publisher_db sysname, @publication sysname, @trigname sysname, @procname sysname, @proc_owner sysname, @cftproc sysname, @agent_id int, @identity_col sysname = NULL, @ts_col sysname = NULL, @filter_clause nvarchar(4000), @primary_key_bitmap varbinary(4000) ) as BEGIN declare @colname sysname ,@cmd nvarchar(4000) ,@ins_cmd nvarchar(4000) ,@columns binary(32) ,@outvars nvarchar(4000) ,@rc int ,@qualname nvarchar(512) ,@fisqueued bit set nocount on -- -- security check -- exec @rc = sp_MSreplcheck_subscribe if @@error <> 0 or @rc <> 0 begin return (1) end exec sp_MSget_qualified_name @objid, @qualname OUTPUT if (LOWER(@cftproc) = N'null') begin select @fisqueued = 0 ,@cftproc = NULL end else select @fisqueued = 1 if @ts_col in ('null','NULL') select @ts_col = null if @identity_col in ('null','NULL') select @identity_col = null -- Create temp table create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- 1st preamble common to all synctran procs exec dbo.sp_MSscript_begintrig1 @trigname, @objid, @procname, @filter_clause, 'ins', @fisqueued -- 2nd preamble common to all synctran procs exec dbo.sp_MSscript_begintrig2 @publisher, @publisher_db, @publication, @objid, 'ins',@agent_id, @fisqueued -- script single row handling exec @rc = dbo.sp_MSscript_singlerow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, @cftproc, @identity_col, @ts_col, 'ins', @primary_key_bitmap -- script multi-row handling exec @rc = dbo.sp_MSscript_multirow_trigger @objid, @publisher, @publisher_db, @publication, @procname, @proc_owner, @cftproc, @identity_col, @ts_col, 'ins', @primary_key_bitmap -- script end of trigger exec dbo.sp_MSscript_endtrig -- send fragments to client select procedure_text from #proctext order by c1 asc END go exec dbo.sp_MS_marksystemobject sp_MSscript_sync_ins_trig go grant execute on dbo.sp_MSscript_sync_ins_trig to public go -------------------------------------------------------------------------------- --. sp_MSscript_sync_upd_trig -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_sync_upd_trig') drop procedure sp_MSscript_sync_upd_trig go raiserror('Creating procedure sp_MSscript_sync_upd_trig', 0,1) go create procedure sp_MSscript_sync_upd_trig ( @objid int, @publisher sysname, @publisher_db sysname, @publication sysname, @trigname sysname, @procname sysname, @proc_owner sysname, @cftproc sysname, @agent_id int, @identity_col sysname = NULL, @ts_col sysname = NULL, @filter_clause nvarchar(4000), @primary_key_bitmap varbinary(4000) ) as BEGIN declare @colname sysname ,@cmd nvarchar(4000) ,@ins_cmd nvarchar(4000) ,@columns binary(32) ,@outvars nvarchar(4000) ,@rc int ,@qualname nvarchar(512) ,@fisqueued bit set nocount on -- -- security check -- exec @rc = sp_MSreplcheck_subscribe if @@error <> 0 or @rc <> 0 begin return (1) end exec sp_MSget_qualified_name @objid, @qualname OUTPUT if (LOWER(@cftproc) = N'null') begin select @fisqueued = 0 ,@cftproc = NULL end else select @fisqueued = 1 if @ts_col in ('null','NULL') select @ts_col = null if @identity_col in ('null','NULL') select @identity_col = null -- Create temp table create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- 1st preamble common to all synctran procs exec dbo.sp_MSscript_begintrig1 @trigname, @objid, @procname, @filter_clause, 'upd', @fisqueued -- prevent updating of unique index when 'row compare' conflict detection, since it would trickle -- back as a del/insert, and fail /* if @ts_col is null begin insert into #proctext(procedure_text) values(N' ') -- exec dbo.sp_MSscript_trigger_update_checks @objid, null, null, 'pk', 0 end */ -- 2nd preamble common to all synctran procs exec dbo.sp_MSscript_begintrig2 @publisher, @publisher_db, @publication, @objid, 'upd',@agent_id, @fisqueued -- script single row handling exec @rc = dbo.sp_MSscript_singlerow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, @cftproc, @identity_col, @ts_col, 'upd', @primary_key_bitmap -- script multi-row handling exec @rc = dbo.sp_MSscript_multirow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, @cftproc, @identity_col, @ts_col, 'upd', @primary_key_bitmap -- script end of trigger exec dbo.sp_MSscript_endtrig -- send fragments to client select procedure_text from #proctext order by c1 asc END go exec dbo.sp_MS_marksystemobject sp_MSscript_sync_upd_trig go grant execute on dbo.sp_MSscript_sync_upd_trig to public go -------------------------------------------------------------------------------- --. sp_check_sync_trigger -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_check_sync_trigger') revoke exec on dbo.sp_check_sync_trigger from public go -------------------------------------------------------------------------------- --. sp_check_for_sync_trigger -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_check_for_sync_trigger') drop procedure sp_check_for_sync_trigger go raiserror('Creating procedure sp_check_for_sync_trigger', 0,1) go create proc sp_check_for_sync_trigger ( @tabid int, @trigger_op char(10) = NULL OUTPUT ) as begin declare @ins_trigid int declare @upd_trigid int declare @del_trigid int declare @retcode int -- -- security check -- exec @retcode = sp_MSreplcheck_subscribe if @@error <> 0 or @retcode <> 0 begin return (1) end select @trigger_op = NULL select @ins_trigid = id from sysobjects where type = N'TR' and name like N'trg_MSsync_ins_%' and parent_obj = @tabid select @upd_trigid = id from sysobjects where type = N'TR' and name like N'trg_MSsync_upd_%' and parent_obj = @tabid select @del_trigid = id from sysobjects where type = N'TR' and name like N'trg_MSsync_del_%' and parent_obj = @tabid if trigger_nestlevel( @ins_trigid ) > 0 begin select @trigger_op = 'ins' return 1 end else -- if nestlevel of insert trigger on same table > 0 then bail if trigger_nestlevel( @upd_trigid ) > 0 begin select @trigger_op = 'upd' return 1 end else if trigger_nestlevel( @del_trigid ) > 0 begin select @trigger_op = 'del' return 1 end else return 0 end go exec dbo.sp_MS_marksystemobject sp_check_for_sync_trigger go grant execute on dbo.sp_check_for_sync_trigger to public go -------------------------------------------------------------------------------- --. sp_MShelpmergedynamicsnapshotjob -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MShelpmergedynamicsnapshotjob') drop procedure sp_MShelpmergedynamicsnapshotjob go raiserror('Creating procedure sp_MShelpmergedynamicsnapshotjob', 0,1) go create procedure sp_MShelpmergedynamicsnapshotjob ( @publication sysname = N'%', @dynamic_snapshot_jobname sysname = N'%', @dynamic_snapshot_jobid uniqueidentifier = null ) as begin declare @retcode int set nocount on /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) if not exists (select * from sysobjects where name = 'sysmergepublications') begin return 0 end select 'id' = j.id, 'job_name' = j.name, 'job_id' = j.job_id, 'dynamic_filter_login' = j.dynamic_filter_login, 'dynamic_filter_hostname' = j.dynamic_filter_hostname, 'dynamic_snapshot_location' = j.dynamic_snapshot_location from sysmergepublications p inner join MSdynamicsnapshotjobs j on p.pubid = j.pubid where (p.name = @publication or @publication = N'%') and (j.name = @dynamic_snapshot_jobname or @dynamic_snapshot_jobname = N'%') and (j.job_id = @dynamic_snapshot_jobid or @dynamic_snapshot_jobid is null) if @@error <> 0 return (1) else return (0) end go exec dbo.sp_MS_marksystemobject sp_MShelpmergedynamicsnapshotjob go grant execute on dbo.sp_MShelpmergedynamicsnapshotjob to public go -------------------------------------------------------------------------------- --. sp_addtabletocontents -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_addtabletocontents') drop procedure sp_addtabletocontents go raiserror('Creating procedure sp_addtabletocontents', 0,1) go create procedure sp_addtabletocontents (@table_name sysname, @owner_name sysname = NULL) AS declare @qualified_table_name nvarchar(270) declare @tablenick int declare @tablenickstr nvarchar(12) declare @repl_nick int declare @lineage varbinary(249) declare @colv varbinary(2000) declare @coltrack int declare @objid int declare @maxcolid int declare @retcode int declare @gen int /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) set nocount on create table #temp_cont(rowguid uniqueidentifier) execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL begin RAISERROR (14055, 11, -1) RETURN(1) end if @owner_name is NULL begin select @owner_name = user_name(uid) from sysobjects where name = @table_name end set @qualified_table_name = QUOTENAME(@owner_name) + '.' + QUOTENAME(@table_name) set @objid = object_id(@qualified_table_name) if @objid is NULL return (1) select @gen = max(gen_cur), @tablenick = max(nickname), @coltrack = max(column_tracking) from sysmergearticles where objid = @objid if @gen is null set @gen = 0 select @maxcolid = max(colid) from syscolumns where id = @objid if @coltrack = 1 set @colv = { fn INITCOLVS(@maxcolid, @repl_nick) } else set @colv = NULL set @lineage = { fn UPDATELINEAGE(0x0, @repl_nick, 1) } set @tablenickstr = convert(nchar, @tablenick) exec ('insert into #temp_cont(rowguid) select RowGuidCol from ' + @qualified_table_name + ' where RowGuidCol not in (select rowguid from MSmerge_contents where tablenick = ' + @tablenickstr + ')') insert into MSmerge_contents (tablenick, rowguid, generation, joinchangegen, lineage, colv1) select @tablenick, rowguid, @gen, @gen, @lineage, @colv from #temp_cont drop table #temp_cont GO exec dbo.sp_MS_marksystemobject sp_addtabletocontents go grant exec on dbo.sp_addtabletocontents to public go -------------------------------------------------------------------------------- --. sp_MSaddpubtocontents -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddpubtocontents') drop procedure sp_MSaddpubtocontents go raiserror('Creating procedure sp_MSaddpubtocontents', 0,1) go create procedure sp_MSaddpubtocontents (@publication sysname) AS declare @pubid uniqueidentifier declare @tablenick int declare @retcode int declare @objid int declare @owner sysname declare @table sysname set nocount on /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (20026, 11, -1, @publication) return (1) end select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid while @tablenick is not null begin select @objid = objid from sysmergearticles where pubid = @pubid and nickname = @tablenick select @owner = user_name(uid) from sysobjects where id = @objid set @table = OBJECT_NAME(@objid) exec @retcode = dbo.sp_addtabletocontents @table, @owner IF @@ERROR <> 0 or @retcode <> 0 return (1) select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid and nickname > @tablenick end GO exec dbo.sp_MS_marksystemobject sp_MSaddpubtocontents go grant exec on dbo.sp_MSaddpubtocontents to public go -------------------------------------------------------------------------------- --. sp_MScomputemergeunresolvedrefs -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MScomputemergeunresolvedrefs') drop procedure sp_MScomputemergeunresolvedrefs go raiserror(15339,-1,-1,'sp_MScomputemergeunresolvedrefs') GO CREATE PROCEDURE sp_MScomputemergeunresolvedrefs @publication sysname, -- Must provide the publication name @article sysname = '%' -- '%' means all articles in the specified publication, otherwise an exact match is performed AS SET NOCOUNT ON DECLARE @pubid uniqueidentifier -- Parameter check: @publication IF @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END SELECT @pubid = NULL -- Get the pubid of the publication SELECT @pubid = pubid FROM sysmergepublications WHERE name = @publication AND UPPER(publisher) = UPPER(@@SERVERNAME) AND publisher_db = DB_NAME() IF @pubid IS NULL BEGIN RAISERROR (20026, 11, -1, @publication) RETURN (1) END if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end SELECT DISTINCT 'article' = a.name, 'dependent object' = o.name, 'dependent object owner' = u.name, 'dependent objectid' = o.id FROM dbo.sysmergeextendedarticlesview a INNER JOIN sysdepends dep ON a.objid = dep.id AND a.pubid = @pubid AND (@article = '%' OR name = @article) AND dep.depid NOT IN (SELECT objid FROM dbo.sysmergeextendedarticlesview WHERE pubid = @pubid AND (@article = '%' OR name = @article)) INNER JOIN sysobjects o ON dep.depid = o.id INNER JOIN sysusers u ON u.uid = o.uid GO exec dbo.sp_MS_marksystemobject sp_MScomputemergeunresolvedrefs go grant exec on dbo.sp_MScomputemergeunresolvedrefs to public go -------------------------------------------------------------------------------- -- procedures from rlrecon.sql regarding security stuff -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSfetchidentityrange') drop procedure sp_MSfetchidentityrange raiserror('Creating procedure sp_MSfetchidentityrange', 0,1) GO CREATE PROCEDURE sp_MSfetchidentityrange @tablename sysname, @adjust_only bit AS declare @retcode int declare @objid int declare @distributor sysname declare @distribdb sysname declare @publisher sysname declare @publisher_db sysname declare @next_seed bigint declare @range bigint declare @threshold int declare @tablenick int declare @distproc nvarchar(300) declare @identity_support int select @publisher=@@SERVERNAME select @publisher_db=db_name() select @objid = object_id(@tablename) select @identity_support=identity_support, @tablenick = nickname from sysmergearticles where objid=@objid /* ** do permission checking */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 return (1) SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange' exec @retcode = @distproc @publisher=@publisher, @publisher_db=@publisher_db, @tablename=@tablename, @adjust_only=1, --do adjust only @next_seed=@next_seed OUTPUT, @range=@range OUTPUT, @threshold=@threshold OUTPUT IF @@ERROR <> 0 OR @retcode <> 0 return (1) --initialize article collection for agents. if @adjust_only=0 select @identity_support, @next_seed-range, range, threshold from MSrepl_identity_range where objid = @objid GO exec dbo.sp_MS_marksystemobject sp_MSfetchidentityrange go grant exec on dbo.sp_MSfetchidentityrange to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MScheckidentityrange') drop procedure sp_MScheckidentityrange raiserror('Creating procedure sp_MScheckidentityrange', 0,1) GO CREATE PROCEDURE sp_MScheckidentityrange @pubid uniqueidentifier, @artname sysname, @next_seed bigint, @range bigint, @threshold int, @checkonly int AS declare @colid int declare @colname sysname declare @retcode int declare @objid int declare @identity_so_far bigint declare @current_max bigint declare @max_identity bigint declare @tablename sysname declare @flag smallint declare @distributor sysname declare @distribdb sysname declare @republisher bit declare @publisher sysname declare @publisher_db sysname declare @distproc nvarchar(300) declare @pub_range bigint /* ** Check to see if current publication has permission */ if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end select @objid = objid from sysmergearticles where pubid=@pubid and name=@artname select @flag = 1 select @republisher = 0 select @tablename=object_name(@objid) if exists (select * from sysmergearticles where objid=@objid and pubid <>@pubid and pubid in (select pubid from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name())) begin select @publisher=@@SERVERNAME select @publisher_db=db_name() select @republisher = 1 exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 begin raiserror(14071, 16, -1) return (1) end end if @checkonly=1 begin if @republisher=0 begin --current_max is defaulted to max_identity value if not republished at subscribers. select @current_max = current_max from MSrepl_identity_range where objid=@objid select @identity_so_far = ident_current(@tablename) if ident_incr(@tablename) < 0 select @flag = -1 if @flag * 100 * (@identity_so_far - (@current_max + 1 - @range))/@range > @threshold select 1 --needs bump up else select 0 --no need to bump up end else begin select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0, @max_identity=0 --make them non-NULL SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity' exec @retcode= @distproc @publisher=@@SERVERNAME, @publisher_db=@publisher_db, @tablename=@tablename, @range=@range OUTPUT, @max_identity=@max_identity OUTPUT, @next_seed = @next_seed OUTPUT, @pub_range=@pub_range OUTPUT if @retcode<>0 or @@ERROR<>0 begin raiserror(21195, 16, -1) return (1) end if (@max_identity-@next_seed)<@range or (@max_identity-@next_seed)<@pub_range select 1 else select 0 end end else begin if @republisher=0 begin --its current_max value is to be set by sp_addmergearticle, if to be republished. update MSrepl_identity_range set max_identity=@next_seed + @range, next_seed=@next_seed, current_max=@next_seed + @range -1 where objid = @objid exec sp_MSreseed @objid, @next_seed, @range if @@ERROR <> 0 goto FAILURE end else begin SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange' exec @retcode = @distproc @publisher=@publisher, @publisher_db=@publisher_db, @tablename=@tablename, @for_publisher = 2, --for repub case, increment max_identity at distributor side @next_seed = @next_seed, @range=@range OUTPUT, @adjust_only=1 --do adjust only if @retcode<>0 or @@ERROR<>0 begin raiserror(21315, 16, -1, @tablename) return (1) end end end return (0) FAILURE: select 0 return (1) go exec dbo.sp_MS_marksystemobject sp_MScheckidentityrange go grant exec on dbo.sp_MScheckidentityrange to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MShelpmergearticles') drop procedure sp_MShelpmergearticles raiserror('Creating procedure sp_MShelpmergearticles', 0,1) GO CREATE PROCEDURE sp_MShelpmergearticles @publication sysname, @compatibility_level int = 7000000, @pubidin uniqueidentifier = NULL as declare @pubid uniqueidentifier declare @artid uniqueidentifier declare @user_name sysname declare @guid_col sysname declare @identity_support int declare @nickname int declare @identity_so_far bigint declare @next_seed bigint declare @pub_range bigint declare @objid int declare @qualname nvarchar(270) declare @retcode int declare @tablename sysname declare @range bigint declare @current_max bigint declare @threshold int declare @distributor sysname declare @distribdb sysname declare @distproc nvarchar(300) declare @flag smallint declare @c_max bigint declare @n_seed bigint declare @db_name sysname declare @has_joins int declare @article_filter_category int declare @haspartfilters int declare @grouppartfilterarticles int declare @injoinfilters int declare @nofilters int declare @objid_looper int declare @indexcol int declare @rowcount1 int declare @rowcount2 int declare @tmp_table TABLE (tablename sysname, user_name sysname, guid_col sysname NULL, next_seed bigint, range bigint, threshold int, artid uniqueidentifier, pubid uniqueidentifier, has_joins int, article_filter_category int, objid int, has_relation_with_joinarticles int default 0, node_visited bit default 0) declare @worktable TABLE (objid int NOT NULL, indexcol int) set @nofilters = 1 set @haspartfilters = 2 set @injoinfilters = 4 set @grouppartfilterarticles = 8 /* ** To public. */ set nocount on if (@publication is null) begin RAISERROR(14003, 16, -1) return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 return (1) select @db_name = db_name() if @pubidin is not NULL set @pubid = @pubidin else select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name if (@pubid is null) begin RAISERROR (20026, 11, -1, @publication) return (1) end /* ** Check to see if current publication has permission */ if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end select TOP 1 @artid=artid from sysmergearticles where pubid=@pubid order by nickname ASC while (@artid is not NULL) begin select @objid=objid, @nickname=nickname, @identity_support=identity_support from sysmergearticles where pubid=@pubid and artid=@artid select @tablename=object_name(@objid) select @user_name=user_name(uid) from sysobjects where id=@objid select @qualname=QUOTENAME(@user_name) + '.' + QUOTENAME(@tablename) select @next_seed=NULL, @range=NULL, @threshold=NULL --null if not being updated later if @identity_support=1 and exists (select * from sysmergepublications where pubid = @pubid and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name) begin select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0 --make them non-NULL SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity' exec @retcode= @distproc @publisher=@@SERVERNAME, @publisher_db=@db_name, @tablename=@tablename, @range=@range OUTPUT, @current_max=@current_max OUTPUT, @threshold=@threshold OUTPUT, @next_seed = @next_seed OUTPUT, @pub_range=@pub_range OUTPUT if @retcode<>0 or @@ERROR<>0 return (1) select @identity_so_far = IDENT_CURRENT(@tablename) select @flag=1 if ident_incr(@tablename) < 0 select @flag = -1 -- we attempted to adjust publisher side identity range based on its threshodl if needed -- however, non-dbo/sysadmin's will not be able to do so. -- so this is limited to dbos or sysadmins. if @flag * 100 * (@identity_so_far - (@current_max + 1 - @pub_range))/@pub_range > @threshold and ((is_srvrolemember('sysadmin') = 1) or (is_member('db_owner') = 1)) begin select @c_max=@next_seed + @pub_range - 1 select @n_seed=@next_seed + @pub_range SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity' exec @retcode=@distproc @publisher=@@SERVERNAME, @publisher_db=@db_name, @tablename=@tablename, @current_max=@c_max, @next_seed = @n_seed if @retcode<>0 or @@ERROR<>0 return (1) exec @retcode=sp_MSreseed @objid, @next_seed, @pub_range, 1 if @@ERROR <> 0 or @retcode<>0 begin raiserror(21197, 16, -1) return (1) end select @next_seed=@next_seed + @pub_range end end else if @identity_support=1 and not exists (select * from sysmergepublications where pubid = @pubid and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name) begin /* This is the case of a message based subscriber acting like publisher */ select @range = range, @threshold = threshold, @next_seed = next_seed from MSrepl_identity_range where objid = @objid end if exists (select * from sysmergesubsetfilters where join_nickname = @nickname) set @has_joins = 1 else set @has_joins = 0 -- reset for subsequent bitwise OR operations. set @article_filter_category = 0 if exists (select * from sysmergesubsetfilters where pubid = @pubid and (join_nickname = @nickname or art_nickname = @nickname)) set @article_filter_category = (@article_filter_category | @injoinfilters) if exists (select * from sysmergearticles where pubid = @pubid and nickname = @nickname and datalength(subset_filterclause) > 1) set @article_filter_category = (@article_filter_category | @haspartfilters | @grouppartfilterarticles) if (@article_filter_category = 0) set @article_filter_category = @nofilters select @guid_col=name from syscolumns where id=@objid and ColumnProperty(@objid, name, 'IsRowGuidCol')=1 insert @tmp_table values(@tablename, @user_name, @guid_col, @next_seed, @range, @threshold, @artid, @pubid, @has_joins, @article_filter_category, @objid, 0, 0) if @@ERROR<>0 begin raiserror(21197, 16, -1) return (1) end select @artid = NULL select TOP 1 @artid=artid from sysmergearticles where pubid=@pubid and nickname>@nickname order by nickname ASC end -- Find articles that have no relations (in either direction - referring or referenced) with any articles in the join filter category. if exists (select * from @tmp_table where (article_filter_category & @injoinfilters) = @injoinfilters) begin --create unique index #uncworktable on @worktable(objid, indexcol) update @tmp_table set node_visited = 1 where objid not in (select fkeyid from sysreferences) and objid not in (select rkeyid from sysreferences) and (article_filter_category & @injoinfilters) = 0 -- get the min objid from the temp table of all articles select @objid_looper = min(objid) from @tmp_table where node_visited = 0 while (@objid_looper is not null) begin delete from @worktable select @indexcol = 0 insert into @worktable values (@objid_looper, @indexcol) -- find all the objects referenced by this object and all objects that reference this object. insert into @worktable select distinct rkeyid, @indexcol+1 from sysreferences where fkeyid = @objid_looper and rkeyid not in (select objid from @worktable) select @rowcount1 = @@rowcount insert into @worktable select distinct fkeyid, @indexcol+1 from sysreferences where rkeyid = @objid_looper and fkeyid not in (select objid from @worktable) select @rowcount2 = @@rowcount while (@rowcount1 <> 0 or @rowcount2 <> 0) begin select @indexcol = @indexcol+1 insert into @worktable select distinct s.rkeyid, @indexcol+1 from sysreferences s, @worktable w, @tmp_table t where s.fkeyid = w.objid and w.objid = t.objid and w.indexcol = @indexcol and t.node_visited = 0 and s.rkeyid not in (select objid from @worktable) select @rowcount1 = @@rowcount insert into @worktable select distinct s.fkeyid, @indexcol+1 from sysreferences s, @worktable w, @tmp_table t where s.rkeyid = w.objid and w.objid = t.objid and w.indexcol = @indexcol and t.node_visited = 0 and s.fkeyid not in (select objid from @worktable) select @rowcount2 = @@rowcount end if exists (select * from @worktable w, @tmp_table t where w.objid = t.objid and (t.article_filter_category & @injoinfilters) = @injoinfilters) begin -- all articles in @worktable have a direct or indirect relation with at least one object in the join articles category. update @tmp_table set node_visited = 1, has_relation_with_joinarticles = 1 from @tmp_table t, @worktable w where w.objid = t.objid end else begin -- none of the articles in @worktable has any relation (direct or indirect) with any article in the join articles category. update @tmp_table set node_visited = 1, has_relation_with_joinarticles = 0 from @tmp_table t, @worktable w where w.objid = t.objid end -- process more unvisited articles from @tmp_table select @objid_looper = min(objid) from @tmp_table where objid > @objid_looper and node_visited = 0 end end /* If the 7.0 merge agent is making this call then we need to make sure that the CLSID of the sp resolver is the old one and not the new one */ if @compatibility_level = 7000000 begin begin transaction update sysmergearticles set resolver_clsid = '{6F31CE30-7BE4-11d1-9B0A-00C04FC2DEB3}' where article_resolver = 'Microsoft SQLServer Stored Procedure Resolver' select name, t.tablename, t.user_name, a.artid, pre_creation_command, a.pubid, nickname, column_tracking, status, resolver_clsid, conflict_script, conflict_table, insert_proc, update_proc, select_proc, destination_object, missing_col_count, missing_cols, t.guid_col, article_resolver, resolver_info, subset_filterclause, has_joins, excluded_col_count, excluded_cols, destination_owner, identity_support, t.next_seed, t.range, t.threshold, verify_resolver_signature, allow_interactive_resolver, fast_multicol_updateproc, check_permissions, t.article_filter_category, t.has_relation_with_joinarticles from sysmergearticles a, @tmp_table t where a.artid=t.artid and a.pubid=t.pubid order by a.nickname rollback transaction end else begin select name, t.tablename, t.user_name, a.artid, pre_creation_command, a.pubid, nickname, column_tracking, status, resolver_clsid, conflict_script, conflict_table, insert_proc, update_proc, select_proc, destination_object, missing_col_count, missing_cols, t.guid_col, article_resolver, resolver_info, subset_filterclause, has_joins, excluded_col_count, excluded_cols, destination_owner, identity_support, t.next_seed, t.range, t.threshold, verify_resolver_signature, allow_interactive_resolver, fast_multicol_updateproc, check_permissions, t.article_filter_category, t.has_relation_with_joinarticles from sysmergearticles a, @tmp_table t where a.artid=t.artid and a.pubid=t.pubid order by a.nickname end return (0) go exec dbo.sp_MS_marksystemobject sp_MShelpmergearticles go grant exec on dbo.sp_MShelpmergearticles to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MScreateretry') drop procedure sp_MScreateretry go raiserror('Creating procedure sp_MScreateretry', 0,1) GO CREATE PROCEDURE sp_MScreateretry as declare @tname sysname declare @pname sysname declare @tempname sysname declare @guid uniqueidentifier declare @guidstr varchar(40) declare @retcode smallint /* ** Check to see if current publication has permission */ if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)}) begin RAISERROR (14126, 11, -1) return (1) end set @guid = newid() exec @retcode=sp_MSguidtostr @guid, @guidstr out if @retcode<>0 or @@ERROR<>0 return (1) set @tempname = '##retry_' + @guidstr exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out if (@@error <> 0) OR @retcode <> 0 begin RAISERROR(15001, 16, -1, 'sp_MSuniquetempname') return (1) end exec ('create table ' + @tempname + ' (tablenick int NOT NULL, rowguid uniqueidentifier ROWGUIDCOL default newid() not null, errcode int NOT NULL, errtext nvarchar(255) NULL, type tinyint NOT NULL)' ) if (@@error <> 0) begin RAISERROR(15001, 16, -1, @tempname) return (1) end set @tname = @tempname set @tempname = '##insert_' + @guidstr exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out if (@@error <> 0) begin RAISERROR(15001, 16, -1, 'sp_MSuniquetempname') return (1) end exec @retcode = dbo.sp_MSmaketempinsertproc @tname, @tempname if @@ERROR <>0 or @retcode<>0 return (1) select @pname = @tempname select @tname, @pname return (0) go exec dbo.sp_MS_marksystemobject sp_MScreateretry go grant exec on dbo.sp_MScreateretry to public if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdropretry') drop procedure sp_MSdropretry raiserror('Creating procedure sp_MSdropretry', 0,1) GO CREATE PROCEDURE sp_MSdropretry (@tname sysname, @pname sysname) as declare @retcode int /* ** To public */ if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)}) begin RAISERROR (14126, 11, -1) return (1) end exec ('drop table ' + @tname) if @@ERROR <> 0 return(1) exec ('drop procedure ' + @pname) if @@ERROR <> 0 return(1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSdropretry go grant exec on dbo.sp_MSdropretry to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumretries') drop procedure sp_MSenumretries raiserror('Creating procedure sp_MSenumretries', 0,1) GO CREATE PROCEDURE sp_MSenumretries (@tname nvarchar(386), @maxrows int, @tablenick int, @rowguid uniqueidentifier) as declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) declare @retcode int /* ** do permission checking */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) /* ** Modify temp table, granted to public. */ declare @selecttop nvarchar(20) if (@maxrows = 0) set @selecttop= 'select' else set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) if (@tablenick < 1) begin execute (@selecttop + ' tablenick, rowguidcol, errcode, errtext, type from ' + @tname + ' order by tablenick, rowguidcol') IF @@ERROR <>0 RETURN (1) end else begin set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' execute (@selecttop + ' tablenick, rowguidcol, errcode, errtext, type from ' + @tname + ' where (tablenick = ' + @tnstring + ' and rowguidcol > ' + @rgstring + ') or tablenick > ' + @tnstring + ' order by tablenick, rowguidcol' ) if @@ERROR <> 0 RETURN (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumretries go grant exec on dbo.sp_MSenumretries to public if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdeletepushagent') drop procedure sp_MSdeletepushagent go raiserror('Creating procedure sp_MSdeletepushagent', 0,1) GO /* ** This procedure is obselete for dropping push agent at distribution database. ** If we were to recover, don't use server id as parameter for RPC into distributor. ** Use server name instead. */ CREATE PROCEDURE sp_MSdeletepushagent ( @publisher sysname, @publisher_db sysname, @publication sysname, @subscriber sysname, @subscriber_db sysname ) AS declare @distributor sysname declare @distribdb sysname declare @pubid uniqueidentifier declare @distproc nvarchar(300) declare @pub_srvid smallint declare @sub_srvid smallint declare @retcode smallint /* ** Do permission checking */ exec @retcode=sp_MSreplcheck_publish if @retcode<>0 or @@ERROR<>0 return (1) EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 return (1) select @pub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default select @sub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_agent_entry' EXEC @retcode = @distproc @pub_srvid, @publisher_db, @publication, @sub_srvid, @subscriber_db IF @@ERROR <> 0 OR @retcode <> 0 return (1) return (0) GO exec dbo.sp_MS_marksystemobject sp_MSdeletepushagent go grant exec on dbo.sp_MSdeletepushagent to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetlastrecgen') drop procedure sp_MSgetlastrecgen raiserror('Creating procedure sp_MSgetlastrecgen', 0,1) GO CREATE PROCEDURE sp_MSgetlastrecgen (@repid uniqueidentifier) as declare @pubid uniqueidentifier declare @pubname sysname declare @status int declare @retcode int /* ** do permission checking */ exec @retcode=sp_MSreplcheck_connection @repid = @repid if @retcode<>0 or @@ERROR<>0 return (1) if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end /* ** Check the publication status at the publisher - if it is inactive ( say because of a ** metadata cleanup event then return an error so the current merge will quit. */ select @pubid = pubid from sysmergesubscriptions where subid = @repid if (@pubid is not null) begin EXEC @retcode = dbo.sp_MScheckatpublisher @pubid IF @retcode = 0 BEGIN select @pubname = name, @status = status from sysmergepublications where pubid = @pubid if @status = 0 begin RAISERROR(21505, 16, -1, @pubname) return (1) end END end select recgen, recguid from MSmerge_replinfo where repid = @repid return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetlastrecgen go grant exec on dbo.sp_MSgetlastrecgen to public if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetlastsentrecgens') drop procedure sp_MSgetlastsentrecgens raiserror('Creating procedure sp_MSgetlastsentrecgens', 0,1) GO CREATE PROCEDURE sp_MSgetlastsentrecgens (@repid uniqueidentifier) as declare @pubid uniqueidentifier declare @pubname sysname declare @status int declare @retcode int if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end /* ** do permission checking */ exec @retcode=sp_MSreplcheck_connection @repid = @repid if @retcode<>0 or @@ERROR<>0 return (1) /* ** Check the publication status at the publisher - if it is inactive ( say because of a ** metadata cleanup event then return an error so the current merge will quit. */ select @pubid = pubid from sysmergesubscriptions where subid = @repid if (@pubid is not null) begin EXEC @retcode = dbo.sp_MScheckatpublisher @pubid IF @retcode = 0 BEGIN select @pubname = name, @status = status from sysmergepublications where pubid = @pubid if @status = 0 begin RAISERROR(21505, 16, -1, @pubname) return (1) end END end select sentgen, sentguid, recgen, recguid from MSmerge_replinfo where repid = @repid return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetlastsentrecgens go grant exec on dbo.sp_MSgetlastsentrecgens to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetlastsentgen') drop procedure sp_MSgetlastsentgen raiserror('Creating procedure sp_MSgetlastsentgen', 0,1) GO CREATE PROCEDURE sp_MSgetlastsentgen (@repid uniqueidentifier) as declare @pubid uniqueidentifier declare @pubname sysname declare @status int declare @retcode int /* ** do permission checking */ exec @retcode=sp_MSreplcheck_connection @repid = @repid if @retcode<>0 or @@ERROR<>0 return (1) if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end /* ** Check the publication status at the publisher - if it is inactive ( say because of a ** metadata cleanup event then return an error so the current merge will quit. */ select @pubid = pubid from sysmergesubscriptions where subid = @repid if (@pubid is not null) begin EXEC @retcode = dbo.sp_MScheckatpublisher @pubid IF @retcode = 0 BEGIN select @pubname = name, @status = status from sysmergepublications where pubid = @pubid if @status = 0 begin RAISERROR(21505, 16, -1, @pubname) return (1) end END end select sentgen, sentguid from MSmerge_replinfo where repid = @repid return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetlastsentgen go grant exec on dbo.sp_MSgetlastsentgen to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumgenerations') drop procedure sp_MSenumgenerations raiserror('Creating procedure sp_MSenumgenerations', 0,1) GO CREATE PROCEDURE sp_MSenumgenerations (@genstart int, @pubid uniqueidentifier, @return_count_of_generations bit = 0) as declare @retcode smallint declare @guidnull uniqueidentifier declare @generation_range TABLE (generation int NOT NULL, guidsrc uniqueidentifier NOT NULL, art_nick int NULL, guidlocal uniqueidentifier NOT NULL, pubid uniqueidentifier NULL, nicknames varbinary(1000) NOT NULL, okaytoskip bit NOT NULL) declare @status int declare @pubname sysname declare @rowcount int set @guidnull = '00000000-0000-0000-0000-000000000000' /* ** Check to see if current publication has permission */ if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end /* ** To public */ if (@genstart is null) begin RAISERROR(14043, 16, -1, '@genstart') return (1) end if (@pubid is null) begin RAISERROR(14043, 16, -1, '@pubid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end /* ** Check the publication status at the publisher - if it is inactive ( say because of a ** metadata cleanup event then return an error so the current merge will quit. */ EXEC @retcode = dbo.sp_MScheckatpublisher @pubid IF @retcode = 0 BEGIN select @pubname = name, @status = status from sysmergepublications where pubid = @pubid if @status = 0 begin RAISERROR(21505, 16, -1, @pubname) return (1) end END insert into @generation_range (generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip) select DISTINCT generation, guidsrc, art_nick, guidlocal, pubid, nicknames, 0 from dbo.MSmerge_genhistory where generation >= @genstart and (art_nick = 0 or art_nick is NULL or art_nick in (select nickname from sysmergearticles where pubid = @pubid)) select @rowcount = @@rowcount if (@return_count_of_generations = 1) select @rowcount -- optimizations -- 1. skip all rows that are for incomplete generations for articles that have no joins. -- 2. skip all rows for join articles if all the join article rows are incomplete generations. update @generation_range set okaytoskip = 1 where art_nick is not null and art_nick <> 0 and guidlocal = @guidnull and ( ( -- 1. skip all rows that are for incomplete generations for articles that have no joins. not exists (select 1 from sysmergesubsetfilters where join_nickname = art_nick or art_nickname = art_nick) ) or ( -- 2. skip all rows for join articles if all the rows for join and joined articles (i.e. the articles represented by join_nickname -- and art_nickname in sysmergesubsetfilters) are incomplete generations. art_nick in (select join_nickname from sysmergesubsetfilters) and not exists ( select 1 from @generation_range b where b.guidlocal <> @guidnull and exists (select 1 from sysmergesubsetfilters where join_nickname = b.art_nick or art_nickname = b.art_nick) and b.generation > @genstart ) ) ) select generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip from @generation_range ORDER BY generation ASC return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumgenerations go grant exec on dbo.sp_MSenumgenerations to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSchecksnapshotstatus') drop procedure sp_MSchecksnapshotstatus raiserror('Creating procedure sp_MSchecksnapshotstatus', 0,1) GO CREATE PROCEDURE sp_MSchecksnapshotstatus @publication sysname AS declare @db_name sysname declare @retention int declare @snapshot_ready int declare @pubid uniqueidentifier declare @last_snapshot datetime select @snapshot_ready = NULL select @db_name = db_name() select @snapshot_ready=snapshot_ready, @retention=retention, @pubid=pubid from sysmergepublications where name=@publication and publisher=@@SERVERNAME and publisher_db=@db_name if @snapshot_ready is NULL select @snapshot_ready=snapshot_ready, @retention=retention, @pubid=pubid from sysmergepublications where name=@publication if @snapshot_ready is NULL begin raiserror (20026, 11, -1, @publication) return (1) end /* ** Check to see if current publication has permission */ if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end if @snapshot_ready=1 and @retention>0 begin select @last_snapshot=last_validated from sysmergesubscriptions where subid=@pubid if dateadd(day, @retention, @last_snapshot)<getdate() select @snapshot_ready=3 /* snapshot is obsolete */ end select @snapshot_ready go exec dbo.sp_MS_marksystemobject sp_MSchecksnapshotstatus go grant exec on dbo.sp_MSchecksnapshotstatus to public if exists (select * from sysobjects where type = 'P' and name = 'sp_MScheckexistsgeneration') drop procedure sp_MScheckexistsgeneration raiserror('Creating procedure sp_MScheckexistsgeneration', 0,1) GO CREATE PROCEDURE sp_MScheckexistsgeneration (@genguid uniqueidentifier, @gen int output, @pubid uniqueidentifier = NULL) as /* ** Check input parameter */ if (@genguid is null) begin RAISERROR(14043, 16, -1, '@genguid') return (1) end /* ** check permission */ if @pubid is not NULL begin if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end end else begin if not exists (select * from dbo.sysmergepublications where 1 = {fn ISPALUSER(pubid)}) begin RAISERROR (14126, 11, -1) return (1) end end /* Normal case : do not qualify by pubid */ if (@pubid IS NULL) select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000' else /* If we are reinitializing from an alternate publisher, check if the subscription has received generations for the alternate publication */ select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000' and ((pubid = @pubid) or (pubid is null)) IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MScheckexistsgeneration go grant exec on dbo.sp_MScheckexistsgeneration to public GO if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumreplicas') drop procedure sp_MSenumreplicas raiserror('Creating procedure sp_MSenumreplicas', 0,1) GO CREATE PROCEDURE sp_MSenumreplicas (@pubid uniqueidentifier) as declare @inactive tinyint /* ** Check to see if current publication has permission */ if ({ fn ISPALUSER(@pubid) } <> 1) begin RAISERROR (14126, 11, -1) return (1) end /* ** To public */ select @inactive = 0 if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select subs.subid, replinfo.replnickname, subs.subscriber_type, subs.subscription_type, subs.priority, replinfo.schemaversion, replinfo.schemaguid, subs.datasource_type, subs.datasource_path, servers.srvname, subs.db_name, subs.status, subs.partnerid, subs.sync_type, subs.description, subs.pubid, subs.publication, subs.distributor from sysmergesubscriptions subs, MSmerge_replinfo replinfo, master..sysservers servers where replinfo.repid = subs.subid and subs.srvid = servers.srvid and subs.status <> @inactive and subs.subscriber_type = 1 order by convert(binary, subs.subid) IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumreplicas go grant exec on dbo.sp_MSenumreplicas to public if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumpartialdeletes') drop procedure sp_MSenumpartialdeletes go raiserror('Creating procedure sp_MSenumpartialdeletes', 0,1) GO CREATE PROCEDURE sp_MSenumpartialdeletes (@maxrows int, @tablenick int, @rowguid uniqueidentifier, @tablenotbelongs nvarchar(255), @bookmark int = NULL, @specified_article_only int = 0) as declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) declare @lowrangestr nvarchar(12) declare @highrangestr nvarchar(12) declare @retcode int /* ** do permission checking */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) /* ** To public. */ declare @selecttop nvarchar(20) if (@maxrows = 0) set @selecttop= 'select' else set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) -- DEBUG insert into MSmerge_debug -- DEBUG (okay, artnick, twhen, comment) -- DEBUG values (0, @tablenick, getdate(), 'sp_MSenumpartialdeletes; maxrows=' + convert(nvarchar, @maxrows) -- DEBUG + ', startguid=' + convert(nchar(36), @rowguid) + ', bookmark=' + convert(nvarchar, @bookmark) -- DEBUG + ', specified_article_only=' + convert(nchar(1), @specified_article_only)) if (@tablenick < 1) begin execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + ' order by tablenick desc, rowguid asc' ) IF @@ERROR <>0 begin -- DEBUG insert into MSmerge_debug (okay, twhen, comment) -- DEBUG values (1, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed') return (1) end -- DEBUG execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, twhen, comment) ' + -- DEBUG @selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, getdate(), ''sp_MSenumpartialdeletes'' -- DEBUG from ' + @tablenotbelongs + ' order by tablenick desc, rowguid asc' ) end else begin set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' /* ** If a 7.0 SP1 Merge agent is calling this sp, it passed a valid bookmark parameter ** Use the bookmark column in the ##belongs_<> table to retrieve the next batch of rows */ if @bookmark is NOT NULL begin set @lowrangestr = convert(nchar, @bookmark) set @highrangestr = convert(nchar, (@bookmark + @maxrows)) if (@specified_article_only = 1) begin -- don't rely on @highrangestr since it will be equal to @lowrangestr if @maxrows=0. execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + ' where tablenick = ' + @tnstring + ' and bookmark > ' + @lowrangestr + ' order by rowguid' ) if @@ERROR<>0 begin -- DEBUG insert into MSmerge_debug (okay, twhen, comment) -- DEBUG values (2, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed') return (1) end -- DEBUG execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) ' + -- DEBUG @selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only = 1'' -- DEBUG from ' + @tablenotbelongs + ' -- DEBUG where tablenick = ' + @tnstring + ' and -- DEBUG bookmark > ' + @lowrangestr + ' -- DEBUG order by rowguid' ) end else begin execute ('select tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + ' where ((tablenick = ' + @tnstring + ' and bookmark > ' + @lowrangestr + ' and bookmark <= ' + @highrangestr + ') or tablenick < ' + @tnstring + ') order by tablenick desc, rowguid asc' ) if @@ERROR<>0 begin -- DEBUG insert into MSmerge_debug (okay, twhen, comment) -- DEBUG values (3, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed') return (1) end -- DEBUG execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) -- DEBUG select 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only <> 1'' -- DEBUG from ' + @tablenotbelongs + ' -- DEBUG where ((tablenick = ' + @tnstring + ' and -- DEBUG bookmark > ' + @lowrangestr + ' and bookmark <= ' + @highrangestr + ') or -- DEBUG tablenick < ' + @tnstring + ') -- DEBUG order by tablenick desc, rowguid asc' ) end end /* ** Backward compatibilty mode : If a 7.0 Merge agent is calling this sp, it will pass a NULL bookmark parameter ** Use the rowguid and set rowcount to retrieve the next batch of rows */ else begin if (@specified_article_only = 1) begin execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + ' where tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + ' order by rowguid' ) IF @@ERROR <>0 begin -- DEBUG insert into MSmerge_debug (okay, twhen, comment) -- DEBUG values (4, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed') return (1) end -- DEBUG execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) ' + -- DEBUG @selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only = 0'' -- DEBUG from ' + @tablenotbelongs + ' -- DEBUG where tablenick = ' + @tnstring + ' and -- DEBUG rowguid > ' + @rgstring + ' -- DEBUG order by rowguid' ) end else begin execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + ' where ((tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ') order by tablenick desc, rowguid asc' ) IF @@ERROR <>0 begin -- DEBUG insert into MSmerge_debug (okay, twhen, comment) -- DEBUG values (5, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed') return (1) end -- DEBUG execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) ' + -- DEBUG @selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only = 0'' -- DEBUG from ' + @tablenotbelongs + ' -- DEBUG where ((tablenick = ' + @tnstring + ' and -- DEBUG rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ') -- DEBUG order by tablenick desc, rowguid asc' ) end end end return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumpartialdeletes go grant exec on dbo.sp_MSenumpartialdeletes to public go if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSaddanonymousreplica') drop procedure sp_MSaddanonymousreplica go raiserror('Creating procedure sp_MSaddanonymousreplica',0,1) GO CREATE PROCEDURE sp_MSaddanonymousreplica (@publication sysname, @publisher sysname, @publisherDB sysname, @anonymous int, @sync_type int = 1, /* sync type is automatic by default */ @preexists bit=0 OUTPUT ) as set nocount on declare @retcode int declare @subscription_type nvarchar(15) declare @sync_typestr nvarchar(15) declare @sub_typeid int declare @pubid uniqueidentifier /* ** need more than PAL to do this. */ exec @retcode = sp_MSreplcheck_subscribe if @@error<>0 or @retcode<>0 return (1) select @preexists = 0 if @anonymous = 1 begin select @subscription_type = 'anonymous' select @sub_typeid = 2 --subscription type value for anonymous end else begin select @subscription_type = 'local' select @sub_typeid = 1 --subscription type value for well known pull end if @sync_type = 1 select @sync_typestr = 'automatic' else select @sync_typestr = 'none' -- this change is made so that we will try to add pull/anonymous subscriptions, even if -- there is a already a subscription for that publication, however the subscription type -- does not match. In this way we can prevent users from using incorrect subscription type -- through command line or merge control. if exists (select * from sysobjects where name='sysmergepublications') begin select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db = @publisherDB if @pubid is not NULL begin /* Check if theres is a subscriptions entry that matches the pubid and current subscription with the right type */ if exists (select * from sysmergesubscriptions where pubid =@pubid and UPPER(subscriber_server) = @@SERVERNAME and db_name = DB_NAME() and subscription_type=@sub_typeid) begin select @preexists = 1 return (0) -- replica exists. end /* ** Check if theres is a subscriptions entry that matches the pubid and current subscription - ** If there is a match and the types are not the same, then return appropriate error. */ else if exists (select * from sysmergesubscriptions where pubid =@pubid and UPPER(subscriber_server) = @@SERVERNAME and db_name = DB_NAME()) begin RAISERROR (21500, 16, -1, @publication) -- replica exists with wrong subscription type select @preexists = 1 return (1) end end end -- Call this SP to add this replica exec @retcode = dbo.sp_addmergepullsubscription @publication = @publication, @publisher = @publisher, @publisher_db=@publisherDB, @subscriber_type =@subscription_type, @sync_type = @sync_typestr IF @retcode<>0 or @@ERROR<>0 return (1) return (0) GO exec dbo.sp_MS_marksystemobject sp_MSaddanonymousreplica go grant execute on dbo.sp_MSaddanonymousreplica to public go -------------------------------------------------------------------------------- --. sp_helpreplfailovermode -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_helpreplfailovermode') drop procedure sp_helpreplfailovermode go raiserror('Creating procedure sp_helpreplfailovermode', 0,1) go create procedure sp_helpreplfailovermode ( @publisher sysname, @publisher_db sysname, @publication sysname, @failover_mode_id tinyint = 0 output, @failover_mode nvarchar(10) = NULL output) as BEGIN declare @subfound bit ,@retcode int -- -- security check -- exec @retcode = sp_MSreplcheck_subscribe if @@error <> 0 or @retcode <> 0 begin return (1) end -- -- Check if the table MSsubscription_agents exists -- if exists (select * from dbo.sysobjects where name = 'MSsubscription_agents') begin -- -- Only valid to get failover_mode, if failover_mode is failover (3,5) -- if exists (select * from dbo.MSsubscription_agents where publisher = @publisher and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) ) select @subfound = 1 else select @subfound = 0 end else select @subfound = 0 -- -- Did we find an entry for initialized failover subscription -- if (@subfound = 0) begin -- -- Three possibilities : uninitialized subscription, non existent subscription -- or a non-mixed mode. Check If we have a PULL uninitialized subscription -- if exists (select * from dbo.sysobjects where name = 'MSreplication_subscriptions') begin if exists (select * from dbo.MSreplication_subscriptions where publisher = @publisher and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) ) begin -- -- unitialized PULL subscription : return the default values -- select @failover_mode_id = 0 select @subfound = 1 end end if (@subfound = 0) begin raiserror ('sp_helpreplfailovermode: Subscription for [%s].[%s].[%s] either has not been initialized or does not exist or does not support mixed mode', 16, 1, @publisher, @publisher_db, @publication) return 1 end end else begin -- -- we found our subscription -- select @failover_mode_id = failover_mode from dbo.MSsubscription_agents where publisher = @publisher and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) -- -- initialize to 'immediate' if necessary -- if @failover_mode_id not in (0, 1) begin raiserror ('sp_helpreplfailovermode: invalid failover_mode value %d for [%s].[%s].[%s], setting to 0 [immediate]', 11, 1, @failover_mode_id, @publisher, @publisher_db, @publication) update dbo.MSsubscription_agents set failover_mode = 0 where publisher = @publisher and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) select @failover_mode_id = 0 end end -- -- prepare the output -- select @failover_mode = case when @failover_mode_id = 0 then N'immediate' when @failover_mode_id = 1 then N'queued' end select N'failover_mode value' = @failover_mode_id, N'failover_mode' = @failover_mode -- -- all done -- return 0 END go exec dbo.sp_MS_marksystemobject sp_helpreplfailovermode go grant execute on dbo.sp_helpreplfailovermode to public go -------------------------------------------------------------------------------- --. sp_setreplfailovermode -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_setreplfailovermode') drop procedure sp_setreplfailovermode go raiserror('Creating procedure sp_setreplfailovermode', 0,1) go create procedure sp_setreplfailovermode ( @publisher sysname, @publisher_db sysname, @publication sysname, @failover_mode nvarchar (10), @override tinyint = 0) as begin set nocount on declare @failover_mode_id tinyint, @current_failover_mode_id bit, @retcode int, @queue_id sysname, @fqueue_empty int, @update_mode int, @queue_server sysname -- -- security check -- exec @retcode = sp_MSreplcheck_subscribe if @@error <> 0 or @retcode <> 0 begin return (1) end -- -- validate @failover_mode -- if @failover_mode not in (N'immediate', N'sync', N'queued') begin raiserror (21184, 16, 1, '@failover_mode', 'immediate', 'sync', 'queued') return 1 end else begin if @failover_mode = 'immediate' or @failover_mode = 'sync' select @failover_mode_id = 0 else if @failover_mode = 'queued' select @failover_mode_id = 1 end -- -- Only valid to get/set failover_mode, -- if update_mode is failover (3,5) -- select @queue_id = queue_id, @queue_server = queue_server, @current_failover_mode_id = failover_mode, @update_mode = update_mode from MSsubscription_agents where UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) -- no such row exists if (@current_failover_mode_id is NULL) begin raiserror (21185, 16, 1) return 1 end -- should have a queue entry if (@queue_id is NULL) begin raiserror(21186, 16, 1, @publisher) return 1 end -- -- do the transition -- if ((@current_failover_mode_id = 0 and @failover_mode_id = 0) or (@current_failover_mode_id = 1 and @failover_mode_id = 1)) begin -- -- Going from immediate to immediate, queued to queued is no-op -- raiserror (21187, 16, 1) end else if (@current_failover_mode_id = 0 and @failover_mode_id = 1) begin -- -- Going from immediate to queued : update MSsubscription_agents -- update MSsubscription_agents set failover_mode = @failover_mode_id where UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) raiserror (21188, 10, 1, 'immediate', 'queued') end else if (@current_failover_mode_id = 1 and @failover_mode_id = 0) begin -- -- Going from queued to immediate : if override is not set -- then check if the queue is empty and then allow if empty. -- If override is set, just update MSsubscription_agents -- if (@override = 0) begin if (@update_mode = 3) begin -- -- MSMQ processing -- prefix the queue_id with queue server in direct format -- and then perform peek in the queue -- select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id exec @retcode = master.dbo.xp_peekqueue @queue_id, @fqueue_empty output, 0 if (@@error != 0 or @retcode != 0) begin raiserror('sp_setreplfailovermode(debug): xp_peekqueue execution failed', 16, 1) return 1 end if (@fqueue_empty != 1) begin raiserror(21189, 16, 1, @queue_id) return 1 end end else begin -- -- SQL Queue processing -- if exists (select * from MSreplication_queue where UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisher_db and publication = @publication ) begin raiserror(21189, 16, 2, @queue_id) return 1 end end end else begin raiserror(21190, 10, 1, 'queued', 'immediate') end -- -- update MSsubscription_agents -- update MSsubscription_agents set failover_mode = @failover_mode_id where publisher = @publisher and publisher_db = @publisher_db and publication = @publication and update_mode in (3,5) raiserror (21188, 10, 1, 'queued', 'immediate') end -- All done return 0 end go exec dbo.sp_MS_marksystemobject sp_setreplfailovermode go grant execute on dbo.sp_helpreplfailovermode to public go -------------------------------------------------------------------------------- --. sp_addqueued_artinfo -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_addqueued_artinfo') drop procedure sp_addqueued_artinfo go raiserror('Creating procedure sp_addqueued_artinfo', 0,1) go CREATE PROCEDURE sp_addqueued_artinfo ( @artid int ,@article sysname ,@publisher sysname ,@publisher_db sysname ,@publication sysname ,@dest_table sysname ,@owner sysname ,@cft_table sysname ,@columns binary(32)) AS BEGIN set nocount on declare @agent_id int ,@update_mode int ,@retcode int -- -- security check -- exec @retcode = sp_MSreplcheck_subscribe if @@error <> 0 or @retcode <> 0 begin return (1) end -- -- Create system table MSsubscription_articles if it does not exist -- IF NOT EXISTS (SELECT * FROM sysobjects WHERE type = 'U' AND name = 'MSsubscription_articles') BEGIN CREATE TABLE dbo.MSsubscription_articles ( agent_id int NOT NULL, -- related entry in MSsubscription_agents artid int NOT NULL, -- article id article sysname, -- article name dest_table sysname, -- destination table owner sysname, cft_table sysname, -- conflict table columns binary(32) ) IF (@@ERROR != 0) begin raiserror('Debug:sp_addqueued_artinfo - create MSsubscription_articles failed', 16, 1) return (1) end CREATE UNIQUE CLUSTERED INDEX ucMSsubscription_articles ON dbo.MSsubscription_articles(agent_id, artid) IF (@@ERROR != 0) begin raiserror('Debug:sp_addqueued_artinfo - create index for MSsubscription_articles failed', 16, 1) return (1) end EXEC dbo.sp_MS_marksystemobject 'MSsubscription_articles' END -- -- insert the row for the given article -- select @agent_id = id, @update_mode = update_mode from MSsubscription_agents where UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisher_db and publication = @publication if (@agent_id IS NULL) begin raiserror('Debug:sp_addqueued_artinfo - agent_id is null for [%s].[%s].[%s]', 16, 1, @publisher, @publisher_db, @publication) return (1) end -- If the subscription is read only or immediate, no need to article info. if @update_mode in (0,1) return 0 -- -- If MSMQ Queued mode - check if the subscriber is compliant for MSMQ 2.0 -- if (@update_mode in (2,3)) begin if ((platform() & 0x1) != 0x1) begin -- -- Win 9X platform -- raiserror(21334, 16, 1, '2.0') return (1) end -- -- Now we use xp_MSver to detect NT OS version -- MSMQ subscription only allowed for platforms that support MSMQ 2.0 -- version 5.0.2195 or higher -- create table #tosversion ( propid int, propname sysname collate database_default, value int, charvalue nvarchar(255) collate database_default) insert into #tosversion (propid, propname, value, charvalue) exec master.dbo.xp_msver N'WindowsVersion' declare @vervalue int ,@lobyte tinyint ,@hibyte tinyint ,@loword smallint ,@hiword smallint -- -- low order byte of low order word = OSmajor, high order byte of low order word = OSminor -- high order word = OSbuild -- select @vervalue = value from #tosversion where propname = N'WindowsVersion' select @loword = (@vervalue & 0xffff) ,@hiword = (@vervalue / 0x10000) & 0xffff select @lobyte = @loword & 0xff ,@hibyte = (@loword / 100) & 0xff drop table #tosversion -- -- check for OS major version -- if (@lobyte < 5) begin raiserror(21334, 16, 2, '2.0') return (1) end -- -- check for OS build version -- if (@lobyte = 5 and @hiword < 2195) begin raiserror(21334, 16, 3, '2.0') return (1) end end -- -- Check for owner - use current user for NULL value -- if (@owner IS NULL or lower(@owner) = N'null' collate database_default) select @owner = user_name() if exists (select * from MSsubscription_articles where agent_id = @agent_id and artid = @artid) delete MSsubscription_articles where agent_id = @agent_id and artid = @artid insert into MSsubscription_articles(agent_id, artid, article, dest_table, owner, cft_table, columns) values (@agent_id, @artid, @article, @dest_table, @owner, @cft_table, @columns) IF (@@ERROR != 0) begin raiserror('Debug:sp_addqueued_artinfo - insert failed', 16, 1) return (1) end -- -- Do the queue initialization here -- this way we can initialize Snapshot/Logbased queued tran from one place -- exec @retcode = dbo.sp_MSreset_queue @publisher, @publisher_db, @publication, @artid IF (@retcode != 0 or @@ERROR != 0) begin raiserror('Debug:sp_addqueued_artinfo - sp_MSreset_queue failed', 16, 1) return (1) end -- -- all done -- return 0 END go exec dbo.sp_MS_marksystemobject sp_addqueued_artinfo go grant execute on dbo.sp_addqueued_artinfo to public go -------------------------------------------------------------------------------- --. sp_MSreset_queued_reinit -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSreset_queued_reinit') drop procedure sp_MSreset_queued_reinit go raiserror('Creating procedure sp_MSreset_queued_reinit', 0,1) go create procedure sp_MSreset_queued_reinit ( @subscriber sysname, -- subscriber server name @subscriber_db sysname, -- subscribing database name. @artid int) -- article id as begin set nocount on declare @srvid int ,@retcode int ,@publication sysname -- -- PAL security check -- Get publication name using artid -- select @publication = p.name from syspublications p join sysarticles a on p.pubid = a.pubid where a.artid = @artid if (@publication is null) begin return 1 end exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication if @@error <> 0 or @retcode <> 0 begin return (1) end select @srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default -- -- set the reinit flag -- update dbo.syssubscriptions set queued_reinit = 0 where artid = @artid and srvid = @srvid and dest_db = @subscriber_db if (@@error != 0) return 1 -- all done return 0 end go exec dbo.sp_MS_marksystemobject sp_MSreset_queued_reinit go grant execute on dbo.sp_MSreset_queued_reinit to public go -------------------------------------------------------------------------------- --. fn_escapecmdshellsymbols -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'FN' and name = N'fn_escapecmdshellsymbols' ) drop function system_function_schema.fn_escapecmdshellsymbols go raiserror('Creating function fn_escapecmdshellsymbols', 0,1) with nowait go -- -- Name: fn_escapecmdshellsymbols -- -- Descriptions: This function returns an escaped version of a given string -- with carets ('^') added in front of all the special -- command shell symbols. In the W2K online help (Start-> -- Help->Index->Command Reference->Command Symbols...), the -- following symbols are listed as special command symbols: -- (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^', N'"') -- -- Parameter: @command_string nvarchar(4000) -- -- Example: select fn_escapecmdshellsymbols(N'The % quick < brown > dog | jumps & over ( the ) lazy ^ fox.') -- will return -- -- The ^% quick ^< brown ^> dog ^| jumps ^& over ^( the ^) lazy ^^ fox -- -- Security: This function is granted to public -- create function system_function_schema.fn_escapecmdshellsymbols( @command_string nvarchar(4000) ) returns nvarchar(4000) as begin declare @escaped_command_string nvarchar(4000), @curr_char nvarchar(1), @curr_char_index int select @escaped_command_string = N'', @curr_char = N'', @curr_char_index = 1 while @curr_char_index <= len(@command_string) begin select @curr_char = substring(@command_string, @curr_char_index, 1) if @curr_char in (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^', N'"') begin select @escaped_command_string = @escaped_command_string + N'^' end select @escaped_command_string = @escaped_command_string + @curr_char select @curr_char_index = @curr_char_index + 1 end return @escaped_command_string end go grant execute on system_function_schema.fn_escapecmdshellsymbols to public -------------------------------------------------------------------------------- --. fn_escapecmdshellsymbolsremovequotes -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'FN' and name = N'fn_escapecmdshellsymbolsremovequotes' ) drop function system_function_schema.fn_escapecmdshellsymbolsremovequotes raiserror('Creating function fn_escapecmdshellsymbolsremovequotes', 0,1) with nowait go -- -- Name: fn_escapecmdshellsymbolsremovequotes -- -- Descriptions: The only difference between this function and -- fn_escapecmdshellsymbols is that "'s are removed from the -- resulting command line. -- -- Parameter: @command_string nvarchar(4000) -- -- Security: This function is granted to public -- create function system_function_schema.fn_escapecmdshellsymbolsremovequotes( @command_string nvarchar(4000) ) returns nvarchar(4000) as begin declare @escaped_command_string nvarchar(4000), @curr_char nvarchar(1), @curr_char_index int select @escaped_command_string = N'', @curr_char = N'', @curr_char_index = 1 while @curr_char_index <= len(@command_string) begin select @curr_char = substring(@command_string, @curr_char_index, 1) if @curr_char in (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^') begin select @escaped_command_string = @escaped_command_string + N'^' end if @curr_char <> '"' begin select @escaped_command_string = @escaped_command_string + @curr_char end select @curr_char_index = @curr_char_index + 1 end return @escaped_command_string end go grant execute on system_function_schema.fn_escapecmdshellsymbolsremovequotes to public -------------------------------------------------------------------------------- --. sp_MSget_file_existence -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSget_file_existence') drop procedure sp_MSget_file_existence go print '' print 'Creating procedure sp_MSget_file_existence' go create procedure sp_MSget_file_existence ( @filename nvarchar(260), @exists bit = 0 output ) AS SET NOCOUNT ON DECLARE @command nvarchar(512) DECLARE @retcode int declare @echo_text nvarchar(20) select @echo_text = 'file_exists' /* ** The return code from xp_cmdshell is not a reliable way to check whether the file exists or ** not. It is always 0 on Win95 as long as xp_cmdshell succeeds. */ select @command = N'if exist "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + N'" echo ' + @echo_text create table #text_ret(cmdoutput nvarchar(20) collate database_default null) insert into #text_ret exec @retcode = master..xp_cmdshell @command if @@error <> 0 or @retcode <> 0 return 1 if exists (select * from #text_ret where ltrim(rtrim(cmdoutput)) = @echo_text) select @exists = 1 else select @exists = 0 drop table #text_ret go EXEC dbo.sp_MS_marksystemobject sp_MSget_file_existence GO -------------------------------------------------------------------------------- --. sp_replicationoption -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_replicationoption') drop procedure sp_replicationoption go raiserror('Creating procedure sp_replicationoption', 0,1) go CREATE PROCEDURE sp_replicationoption ( @optname sysname, @value nvarchar(5), @security_mode int = 0, @login sysname = 'sa', @password sysname = NULL, @reserved nvarchar(20) = NULL ) AS DECLARE @optbit bit DECLARE @osql_path nvarchar(260) DECLARE @osql_cmd1 nvarchar (255) DECLARE @osql_cmd_full nvarchar (255) DECLARE @osql_for_nt int DECLARE @install_path nvarchar (255) DECLARE @retcode int DECLARE @undo_install nvarchar(20) DECLARE @no_scripts nvarchar(10) DECLARE @platform_nt binary SELECT @platform_nt = 0x1 if is_srvrolemember('sysadmin') <> 1 BEGIN RAISERROR (15232, 14, -1) RETURN (1) END SELECT @no_scripts = 'no_scripts' SELECT @undo_install = 'undo_install' IF db_name() <> 'master' BEGIN RAISERROR(5001, 16,-1) GOTO FAILURE END IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('transactional','merge') BEGIN RAISERROR(21014, 16, -1) GOTO FAILURE END IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true','false') BEGIN RAISERROR(14137,16,-1) GOTO FAILURE END IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @optbit = 1 ELSE SELECT @optbit = 0 /* ** Check if the option is set as required already */ IF @reserved <> @undo_install AND EXISTS (SELECT * FROM MSreplication_options WHERE optname = @optname AND value = @optbit) BEGIN IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true' RAISERROR (21015, 10, -1, @optname) ELSE RAISERROR (21016, 10, -1, @optname) GOTO FAILURE END /* Install replication */ IF @optbit = 1 BEGIN IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = @no_scripts GOTO NO_SCRIPTS -- Set the flag for platform IF (( platform() & @platform_nt = @platform_nt )) SELECT @osql_for_nt = 1 ELSE SELECT @osql_for_nt = 0 /* ** Get installation path -- osql client (TOOLS) path */ EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT IF ( @@ERROR <> 0 ) OR ( @retcode <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' ) BEGIN GOTO FAILURE END /* ** Get installation path -- instance specific (INSTALL) directory */ exec @retcode = master.dbo.sp_MSget_setup_paths @sql_path = @install_path output IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path='' BEGIN GOTO FAILURE END /* ** Install replcom.sql and repltran.sql */ IF @security_mode = 1 begin SELECT @osql_cmd1 = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E ' if serverproperty('instancename') is not null SELECT @osql_cmd1 = @osql_cmd1 + ' -S"' + @@SERVERNAME + '" ' end ELSE -- cannot specify -S w/ -E for local execution, SID does not map SELECT @osql_cmd1 = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" ' select @osql_cmd1 = @osql_cmd1 + '-l30 -t30 ' -- Install replcom.sql -- Only apply replcom.sql if it was not applied before. -- '-b' option will make osql stop at errors and return error code -- We must use this option. IF NOT EXISTS (SELECT * FROM MSreplication_options WHERE value = 1) BEGIN -- Initialize the Command IF (@osql_for_nt = 1) SELECT @osql_cmd_full = '" ' ELSE SELECT @osql_cmd_full = ' ' SELECT @osql_cmd_full = @osql_cmd_full + @osql_cmd1 + ' -dmaster' + ' -b ' + ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replcom.sql"' + ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replcom.out"' IF (@osql_for_nt = 1) SELECT @osql_cmd_full = @osql_cmd_full + ' "' EXEC @retcode = master..xp_cmdshell @osql_cmd_full IF @@ERROR<> 0 OR @retcode <> 0 BEGIN RAISERROR (14113, 16, -1, @osql_cmd_full, 'replcom.out') GOTO UNDO_INSTALL END END IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'transactional' BEGIN -- Install repltran.sql IF (@osql_for_nt = 1) SELECT @osql_cmd_full = '" ' ELSE SELECT @osql_cmd_full = ' ' SELECT @osql_cmd_full = @osql_cmd_full + @osql_cmd1 + ' -dmaster' + ' -b ' + ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\repltran.sql"' + ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\repltran.out"' IF (@osql_for_nt = 1) SELECT @osql_cmd_full = @osql_cmd_full + ' "' EXEC @retcode = master..xp_cmdshell @osql_cmd_full IF @@ERROR<> 0 OR @retcode <> 0 BEGIN RAISERROR (14113, 16, -1, @osql_cmd_full, 'repltran.out') GOTO UNDO_INSTALL END END IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge' BEGIN -- Install replmerg.sql IF (@osql_for_nt = 1) SELECT @osql_cmd_full = '" ' ELSE SELECT @osql_cmd_full = ' ' SELECT @osql_cmd_full = @osql_cmd_full + @osql_cmd1 + ' -dmaster' + ' -b ' + ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replmerg.sql"' + ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replmerg.out"' IF (@osql_for_nt = 1) SELECT @osql_cmd_full = @osql_cmd_full + ' "' EXEC @retcode = master..xp_cmdshell @osql_cmd_full IF @@ERROR<> 0 OR @retcode <> 0 BEGIN RAISERROR (14113, 16, -1, @osql_cmd_full, 'replmerg.out') GOTO UNDO_INSTALL END END NO_SCRIPTS: UPDATE MSreplication_options SET value = @optbit WHERE optname = @optname IF @@ERROR <> 0 BEGIN GOTO UNDO_INSTALL END END /* Uninstall replication */ ELSE BEGIN /* ** Make sure no distributor installed before dropping ** replication stored procedures */ IF EXISTS (SELECT * FROM master..sysservers WHERE srvstatus & 8 <> 0) BEGIN RAISERROR (21021, 16, -1) RETURN(1) END UPDATE MSreplication_options SET value = @optbit WHERE optname = @optname IF @@ERROR <> 0 BEGIN GOTO FAILURE END /* *********** Do not drop replication stored procs anymore. IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'transactional' BEGIN if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSdrop_repltran') begin exec @retcode = dbo.sp_MSdrop_repltran if @@ERROR = 0 and @retcode = 0 drop procedure sp_MSdrop_repltran end END IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge' BEGIN if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSdrop_replmerg') begin exec @retcode = dbo.sp_MSdrop_replmerg if @@ERROR = 0 and @retcode = 0 drop procedure sp_MSdrop_replmerg end END IF NOT EXISTS (SELECT * FROM MSreplication_options WHERE value = 1) BEGIN if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSdrop_replcom') begin exec @retcode = dbo.sp_MSdrop_replcom if @@ERROR = 0 and @retcode = 0 drop procedure sp_MSdrop_replcom end END */ END RETURN(0) UNDO_INSTALL: /* This is needed to drop the stored procedures that were created. */ EXEC dbo.sp_replicationoption @optname = @optname, @value = 'false', @reserved = @undo_install FAILURE: RETURN(1) GO exec dbo.sp_MS_marksystemobject sp_replicationoption go grant execute on dbo.sp_replicationoption to public go -------------------------------------------------------------------------------- --. sp_vupgrade_replication -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_vupgrade_replication') drop procedure sp_vupgrade_replication go raiserror('Creating procedure sp_vupgrade_replication', 0,1) GO create procedure sp_vupgrade_replication ( @login sysname = N'sa', @password sysname = N'', @ver_old int = 517, @force_remove tinyint = 0, @security_mode bit = 0 ) as begin /* * Dispatcher proc for handling schema and metadata changes during setup initiated version upgrade * for replication components. Any schema changes to replication system tables may require modifications * here to maintain upgrade path. All modifications called in these procs are within "if exists" checks * making them repeatable for debugging and to support incremental upgrades (e.g. Beta 1 to Beta 2 to RTM) * * If server is a distributor, run new instdist.sql against all distribution dbs. * * This proc gets called by setup at the end of an install over an existing version. */ set nocount on declare @dbname sysname declare @has_dbaccess bit declare @install_path nvarchar(255) declare @osql_path nvarchar(260) declare @osql_cmd nvarchar(512) declare @osql_for_nt int declare @retcode int declare @platform_nt binary declare @db_distbit int declare @ver_min int declare @ver_retention int select @db_distbit = 16 select @platform_nt = 0x1 select @ver_retention = 576 --build # on 9/17 -- raiserror('sp_vupgrade_replication', 0,1) with nowait /* * obsolete check; ver check was to prevent repl upgrade from * versions prior to SQL7.0 Beta 3; check is removed by setting @ver_min = -1 */ select @ver_min= -1 -- change if later wish to support a minimum upgrade version if ( @ver_old < @ver_min ) or ( @force_remove = 1 ) exec dbo.sp_removesrvreplication else begin /* * always need to run instdist.sql to update distribution databases on a distributor * setup must restart in non-single user mode so we can shell out to run instdist.sql scripts */ if exists( select * from master..sysdatabases where category & @db_distbit = @db_distbit ) begin /* ** Get installation path -- osql client (TOOLS) path */ EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT IF ( @@ERROR <> 0 ) OR ( @retcode <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' ) BEGIN RETURN (1) END /* ** Get installation path -- instance specific (INSTALL) directory */ exec @retcode = master.dbo.sp_MSget_setup_paths @sql_path = @install_path output IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path=N'' BEGIN RETURN (1) END -- Set the flag for platform if (( platform() & @platform_nt = @platform_nt )) select @osql_for_nt = 1 else select @osql_for_nt = 0 declare cur_distdb CURSOR LOCAL FAST_FORWARD for select name, has_dbaccess(name) from master..sysdatabases where category & @db_distbit = @db_distbit for read only open cur_distdb fetch cur_distdb into @dbname, @has_dbaccess while ( @@fetch_status <> -1 ) begin -- if distribution database is available upgrade it; if offline error out if ( @has_dbaccess = 1 ) begin raiserror( 21374, 0, 1, @dbname) with nowait /* * Format osql cmd line appropriate for security mode and OS to run instdist.sql against * each distribution database. Instdist.sql will recompile procs and will also do some * schema and metadata upgrade of changed replication tables. Query timeout increased to * make enough time for alter tables in instdist.sql run for upgrade to complete. */ if ( @osql_for_nt = 1 ) select @osql_cmd = N'" "' else select @osql_cmd = N' "' -- Cannot specify -S w/ -E for local execution, SID does not map (nofix) if ( @security_mode = 1 and @osql_for_nt = 1 ) begin select @osql_cmd = @osql_cmd + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E ' if serverproperty('instancename') is not null select @osql_cmd = @osql_cmd + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" ' end else select @osql_cmd = @osql_cmd + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U' + fn_escapecmdshellsymbols(isnull(@login, N'sa')) collate database_default + ' -P' + fn_escapecmdshellsymbols(isnull(@password, N'')) collate database_default + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" ' select @osql_cmd = @osql_cmd + ' -l30 -t120 ' select @osql_cmd = @osql_cmd + ' -b ' + ' -d' + fn_escapecmdshellsymbols(@dbname) collate database_default select @osql_cmd = @osql_cmd + ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.sql"' + ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.out"' if (@osql_for_nt = 1) select @osql_cmd = @osql_cmd + ' "' exec @retcode = master..xp_cmdshell @osql_cmd if @retcode <> 0 or @@error <> 0 begin raiserror (14113, 16, -1, @osql_cmd, 'instdist.out') end /* * Process schema and metadata changes for each distribution database */ select @dbname = quotename(@dbname) exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_distdb') if @@error <> 0 return(1) end else begin /* Report informational message stating distribution ** database is not accessible. */ raiserror( 21378, 10, 1, @dbname) with nowait end fetch next from cur_distdb into @dbname, @has_dbaccess end close cur_distdb deallocate cur_distdb end -- vupgrade_publisher runs at exec @retcode = dbo.sp_vupgrade_publisher @ver_old = @ver_old, @ver_retention = @ver_retention if @retcode<>0 or @@error<>0 return (1) -- Update subscription database schema exec @retcode = dbo.sp_vupgrade_subscription_databases if @retcode <> 0 or @@error <> 0 return (1) end return (0) end go exec dbo.sp_MS_marksystemobject sp_vupgrade_replication go -------------------------------------------------------------------------------- --. sp_MScopysnapshot -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MScopysnapshot') drop procedure sp_MScopysnapshot go raiserror('Creating procedure sp_MScopysnapshot', 0,1) go CREATE PROCEDURE sp_MScopysnapshot ( @source_folder nvarchar(255), @destination_folder nvarchar(255) ) AS BEGIN SET NOCOUNT ON DECLARE @directory_exists bit DECLARE @ftporuncdir nvarchar(5) DECLARE @pubdir nvarchar(255) DECLARE @timestampdir nvarchar(255) DECLARE @bslashindex int DECLARE @bslashindex2 int DECLARE @bslashcounter int DECLARE @command nvarchar(1000) DECLARE @retcode int DECLARE @platform_nt bit IF platform() & 0x1 = 0x1 SELECT @platform_nt = 1 ELSE SELECT @platform_nt = 0 -- If @source_folder is NULL then either the snapshot has not been -- generated or it has been cleaned up IF @source_folder IS NULL OR @source_folder = N'' BEGIN RAISERROR(21289, 16, -1) RETURN (1) END -- Make sure that the @destination folder is not null IF @destination_folder IS NULL OR @destination_folder = N'' BEGIN RAISERROR(21287, 16, -1) RETURN (1) END -- Append backslash to @destination_folder if it is not -- there already IF SUBSTRING(@destination_folder, LEN(@destination_folder), 1) <> N'\' BEGIN SELECT @destination_folder = @destination_folder + N'\' END -- Check if the destination folder exists EXEC sp_MSget_file_existence @destination_folder, @directory_exists OUTPUT IF @directory_exists = 0 BEGIN RAISERROR(21287, 16, -1) RETURN (1) END -- Parse out the last three components in the source folder -- Note that the source_folder must have a trailing backslash SELECT @bslashindex = 1 SELECT @bslashindex2 = 1 SELECT @bslashcounter = 0 WHILE (@bslashindex <> 0) BEGIN SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex + 1) SELECT @bslashcounter = @bslashcounter + 1 IF @bslashcounter > 4 BEGIN SELECT @bslashindex2 = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1) END END SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1) SELECT @ftporuncdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) SELECT @bslashindex2 = @bslashindex SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1) SELECT @pubdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) SELECT @bslashindex2 = @bslashindex SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1) SELECT @timestampdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) SELECT @bslashindex2 = @bslashindex -- Create the subdirectory structure underneath the specified snapshot -- folder. Ignore errors for now, we will check whether the directory -- is successfully created later on. -- Don't suppress output from xp_cmdshell so user knows what's going on -- in case something goes wrong SELECT @destination_folder = @destination_folder + @ftporuncdir + '\' SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"' IF (@platform_nt = 1) SELECT @command = '" ' + @command + ' "' EXEC master..xp_cmdshell @command SELECT @destination_folder = @destination_folder + @pubdir + '\' SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"' IF (@platform_nt = 1) SELECT @command = '" ' + @command + ' "' EXEC master..xp_cmdshell @command SELECT @destination_folder = @destination_folder + @timestampdir + '\' SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"' IF (@platform_nt = 1) SELECT @command = '" ' + @command + ' "' EXEC master..xp_cmdshell @command -- Check if the real destination folder exists EXEC sp_MSget_file_existence @destination_folder, @directory_exists OUTPUT IF @directory_exists = 0 BEGIN RAISERROR(21288, 16, -1) RETURN (1) END -- Do the actual copying SELECT @command = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@source_folder) collate database_default + '*.*" "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"' IF (@platform_nt = 1) SELECT @command = '" ' + @command + ' "' EXEC @retcode = master..xp_cmdshell @command IF @retcode <> 0 RETURN (1) ELSE RETURN (0) END go EXEC dbo.sp_MS_marksystemobject sp_MScopysnapshot go -------------------------------------------------------------------------------- --. sp_copymergesnapshot -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_copymergesnapshot') drop procedure sp_copymergesnapshot go raiserror('Creating procedure sp_copymergesnapshot', 0,1) go CREATE PROCEDURE sp_copymergesnapshot ( @publication sysname, @destination_folder nvarchar(255) ) AS BEGIN SET NOCOUNT ON DECLARE @retcode int DECLARE @source_folder nvarchar(255) SELECT @retcode = 0 EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) CREATE TABLE #snapshot_folders ( id int identity, snapshot_folder nvarchar(255) collate database_default ) IF @@ERROR <> 0 BEGIN RETURN 1 END INSERT INTO #snapshot_folders EXEC @retcode = sp_browsemergesnapshotfolder @publication = @publication IF @retcode <> 0 OR @@ERROR <> 0 BEGIN GOTO Failure END SELECT @source_folder = (select top 1 snapshot_folder FROM #snapshot_folders ORDER BY id ASC) IF @@ERROR <> 0 BEGIN GOTO Failure END SET ROWCOUNT 0 EXEC @retcode = sp_MScopysnapshot @source_folder, @destination_folder IF @retcode <> 0 OR @@ERROR <> 0 BEGIN GOTO Failure END DROP TABLE #snapshot_folders RETURN 0 Failure: SET ROWCOUNT 0 DROP TABLE #snapshot_folders RETURN 1 END GO EXEC dbo.sp_MS_marksystemobject sp_copymergesnapshot go grant execute on dbo.sp_copymergesnapshot to public go -------------------------------------------------------------------------------- --. sp_copysubscription -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_copysubscription') drop procedure sp_copysubscription go print '' print 'Creating procedure sp_copysubscription' go CREATE PROCEDURE sp_copysubscription ( @filename nvarchar(260), @temp_dir nvarchar(260) = NULL, -- Directory contains temp files. If not specified, SQL -- server default data directory will be used. @overwrite_existing_file bit = 0 ) AS SET NOCOUNT ON /* ** Declarations. */ declare @cmd nvarchar(4000) declare @retcode int declare @data_path nvarchar(260) declare @subscriber_srvid int declare @subscriber_db sysname declare @backup_path nvarchar(260) declare @temp_data_path nvarchar(260) declare @temp_log_path nvarchar(260) declare @retention int declare @retention_date datetime declare @pubid uniqueidentifier /* * Initializations */ select @retcode = 0 select @subscriber_srvid = 0 select @subscriber_db = db_name() -- We only support single file attach. Check to make sure -- there are only 2 files, one data file and one log file if (select count(*) from sysfiles) > 2 begin raiserror(21212,16, -1) return 1 end /* Make sure all tran sub allows attach */ declare @publication sysname declare @publisher sysname declare @tran_found bit declare @merge_found bit select @tran_found = 0 select @merge_found = 0 /* ** Make sure all merge subscriptions in the current database ** have allow_subscription_copy set to TRUE ** and there are no push subscriptions. */ if exists (select * from sysobjects where name = 'MSsubscription_agents') begin set @publisher = NULL -- Not using @publication because share agent case. select top 1 @publisher = publisher from MSsubscription_agents where allow_subscription_copy = 0 IF @publisher is not null BEGIN RAISERROR(21236, 16, -1, @publisher) RETURN (1) END set @publisher = null select top 1 @publisher = publisher from MSreplication_subscriptions where subscription_type = 0 IF @publisher is not null BEGIN RAISERROR(21237, 16, -1, @publisher) RETURN (1) END if exists (select * from MSsubscription_agents) select @tran_found = 1 end /* ** Make sure all merge subscriptions in the current database ** have allow_subscription_copy set to TRUE ** and there are no push subscriptions. */ if exists (select * from sysobjects where name = 'sysmergepublications') begin set @publication = NULL select top 1 @publication = name from sysmergepublications where allow_subscription_copy = 0 IF @publication is not null BEGIN RAISERROR (21204, 16, -1, @publication) RETURN (1) END set @publication = null select top 1 @publication = p.name from sysmergepublications p, sysmergesubscriptions s where p.pubid = s.pubid and s.subid <> s.pubid and db_name = db_name() collate database_default and subscriber_server = convert(nvarchar(4000), SERVERPROPERTY('ServerName')) collate database_default and s.subscription_type = 0 IF @publication is not null BEGIN RAISERROR(21238, 16, -1, @publication) RETURN (1) END -- Does db contains subscriptions? if exists (select * from sysmergesubscriptions where subid <> pubid and db_name = db_name() collate database_default and subscriber_server = convert(nvarchar(4000), SERVERPROPERTY('ServerName')) collate database_default) select @merge_found = 1 /* Retention check : Make sure that the subscription copy is not too old */ declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT p.name, p.pubid, p.retention from sysmergepublications p, sysmergesubscriptions s where s.subid=p.pubid and s.pubid=p.pubid for read only open PC fetch PC into @publication, @pubid, @retention WHILE (@@fetch_status <> -1) BEGIN /* Compute the retention period cutoff dates per publication */ select @retention_date = dateadd(day, -@retention, getdate()) if @retention is not NULL and @retention > 0 begin if not exists (select coldate from sysmergearticles , MSmerge_genhistory where nickname = art_nick and coldate > @retention_date and sysmergearticles.pubid = @pubid) begin RAISERROR (21306, 16, -1, @publication) return (1) end end fetch PC into @publication, @pubid, @retention END end if @tran_found = 0 and @merge_found = 0 begin raiserror(21239, 16 , -1) return (1) end -- Security check -- Only DBO or sysadmin can do this -- The user also must have create db permissions. exec @retcode = dbo.sp_MSreplcheck_subscribe IF @retcode <> 0 or @@error <> 0 return 1 if @overwrite_existing_file is null set @overwrite_existing_file = 0 -- Check to see if the file already exists declare @exists bit if @overwrite_existing_file = 0 begin exec @retcode = dbo.sp_MSget_file_existence @filename, @exists output if @@error <> 0 or @retcode <> 0 return 1 if @exists <> 0 begin raiserror(21214, 16, -1, @filename) return 1 end end -- Check to see if have write permissions to the file location. -- Try create the file -- Echo text can be anything. select @cmd = 'echo Subscription copy failed. > "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"' exec @retcode = master.dbo.xp_cmdshell @cmd, NO_OUTPUT if @@error <> 0 or @retcode <> 0 begin raiserror(21247, 16, -1, @filename) select @retcode = 1 goto Cleanup end -- File should be created. exec @retcode = dbo.sp_MSget_file_existence @filename, @exists output if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Cleanup end if @exists = 0 begin raiserror(21247,16, -1, @filename) select @retcode = 1 goto Cleanup end /* ** Get the MSSQL DATA path. Note that users can have a SQLDataRoot directory different from SQLPath */ if @temp_dir is null begin exec @retcode = master.dbo.sp_MSget_setup_paths @data_path = @temp_dir output IF @retcode <> 0 or @@error <> 0 return 1 select @temp_dir = @temp_dir + '\DATA\' end else begin -- Check to make sure working dir is valid. exec @retcode = dbo.sp_MSget_file_existence @temp_dir, @exists output if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Cleanup end if @exists = 0 begin raiserror (21037, 16, -1, @temp_dir) select @retcode = 1 goto Cleanup end if substring(@temp_dir, len(@temp_dir), 1) <> '\' select @temp_dir = @temp_dir + '\' end -- Get temp db name -- Use a guid to avoid name colision. declare @dbname sysname select @dbname = db_name() declare @temp_db_name sysname declare @guid_name nvarchar(36) select @guid_name = convert (nvarchar(36), newid()) select @temp_db_name = 'repl_sub_restore_' + @guid_name select @backup_path = @temp_dir + @temp_db_name + '.bak' -- Create table used to signal attach or restored process to do different things if not exists (select * from sysobjects where name = 'MSreplication_restore_stage') begin CREATE TABLE dbo.MSreplication_restore_stage ( stage_id int -- not used for now ) IF @@ERROR <> 0 return 1 end -- First backup the database to the file given -- Overwrite the existing file with INIT option. BACKUP DATABASE @dbname TO DISK = @backup_path WITH INIT if @@error<> 0 begin select @retcode = 1 goto Cleanup end -- Restore it to a temporary working database -- Get phy data and log file name for the temp db select @temp_data_path = @temp_dir + @temp_db_name + '.mdf' select @temp_log_path = @temp_dir + @temp_db_name + '.ldf' -- Get the command select @cmd = 'restore database ' + quotename(@temp_db_name) + ' from disk = ' + quotename(@backup_path,'''') + ' with replace, move ' -- Get the logical file name for data file. select @cmd = @cmd + quotename(rtrim(name),'''') from sysfiles where (status & 0x40) = 0 -- Use passed in filename as phy data file name for the temp db -- Use the passed in file as phy data file for the temp db select @cmd = @cmd + ' to ' + quotename(@temp_data_path,'''') + ', move ' -- Get the logical file name for the log file select @cmd = @cmd + quotename(rtrim(name),'''') from sysfiles where (status & 0x40) <> 0 -- Use the passed in file as phy file for the temp db select @cmd = @cmd + ' to ' + quotename(@temp_log_path,'''') + ' ' exec (@cmd) if @@error<> 0 begin select @retcode = 1 goto Cleanup end -- Once we successfully restored, we delete to back up file to save disk space. if @backup_path is not null begin select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@backup_path) collate database_default + '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT set @backup_path = null end -- Prepare the database for detach. 2 things will be done -- 1. Set a flag to indicate that this is a prepare sub db for detach -- 2. For merge, create table to store sysservers info for later fixing up after attach select @cmd = quotename(@temp_db_name) + '.dbo.sp_MSprepare_sub_for_detach' exec @retcode = @cmd @subscriber_srvid = @subscriber_srvid, @subscriber_db = @subscriber_db if @retcode<>0 or @@error<>0 begin select @retcode = 1 goto Cleanup end -- Shink the size of the temp db before detach DBCC SHRINKDATABASE (@temp_db_name, 10) if @@error <> 0 goto Cleanup -- detach the database -- Wait for the db to be closed WAITFOR DELAY '00:00:00.500' exec @retcode = sp_detach_db @temp_db_name if @retcode<>0 or @@error<>0 begin select @retcode = 1 goto Cleanup end -- Delete the log file to save disk space if @temp_log_path is not null begin select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_log_path) collate database_default + '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT set @temp_log_path = null end -- Compress the file exec @retcode = master..xp_makecab @cabfilename = @filename, @compression_mode ='mszip', @verbose_level = 0, @filename1 = @temp_data_path if @retcode<>0 or @@error<>0 begin select @retcode = 1 goto Cleanup end Cleanup: if exists (select * from sysobjects where name = 'MSreplication_restore_stage') drop table dbo.MSreplication_restore_stage if exists (select * from master..sysdatabases where name = @temp_db_name collate database_default) begin select @cmd = 'drop database ' + quotename(@temp_db_name) exec (@cmd) end if @backup_path is not null begin select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@backup_path) collate database_default + '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT end if @temp_data_path is not null begin select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_data_path) collate database_default + '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT end if @temp_log_path is not null begin select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_log_path) collate database_default + '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT end if @retcode <> 0 begin select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT end return @retcode go EXEC dbo.sp_MS_marksystemobject sp_copysubscription GO grant execute on dbo.sp_copysubscription to public go -------------------------------------------------------------------------------- --. sp_attachsubscription -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_attachsubscription') drop procedure sp_attachsubscription go print '' print 'Creating procedure sp_attachsubscription' go CREATE PROCEDURE sp_attachsubscription ( @dbname sysname, @filename nvarchar(260), @subscriber_security_mode int = NULL, /* 0 standard; 1 integrated */ @subscriber_login sysname = NULL, @subscriber_password sysname = NULL ) AS SET NOCOUNT ON /* ** Declarations. */ declare @cmd nvarchar(4000) declare @retcode int DECLARE @platform_nt binary declare @copy_created bit declare @exists bit select @platform_nt = 0x1 select @retcode = 0 select @copy_created = 0 select @exists = 0 -- Parameter check: @subscriber_security_mode if @subscriber_security_mode is null begin if ( platform() & @platform_nt ) = @platform_nt select @subscriber_security_mode = 1 else select @subscriber_security_mode = 0 end if ( ( platform() & @platform_nt ) <> @platform_nt and @subscriber_security_mode = 1 ) begin RAISERROR(21038, 16, -1) RETURN (1) end if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '') set @subscriber_login = 'sa' -- Check to make sure the database does not exists. if exists (select * from master..sysdatabases where name = @dbname collate database_default) begin raiserror(20621, 16, -1, @dbname) return (1) end -- Check to see if users has permissions to create database -- permissions() have to be run in master to return create db permission. declare @pm int exec @retcode = master.dbo.sp_executesql N'select @pm = permissions()', N'@pm int output', @pm output if @@error <> 0 or @retcode <> 0 return 1 if @pm & 1 = 0 begin raiserror(20618, 16, -1) return 1 end -- Decompress the file -- We have to copy the file to another location first. -- (cannot use source as destination') declare @temp_copy nvarchar(260) declare @file_dir nvarchar(260) declare @file_name nvarchar(260) declare @dir_cmd nvarchar(260) -- Set @drive_cmd if needed -- Set temp copy to be the file directory first -- Note @file_dir include '\' if (charindex('\', @filename, 1) = 0) begin select @file_dir = '' select @file_name = @filename end else begin select @file_dir = left(@filename,len(@filename) + 1 - charindex('\', reverse(@filename), 1)) select @file_name = right(@filename, len(@filename) - len(@file_dir)) end -- Get guid name declare @guid_name nvarchar(36) select @guid_name = convert (nvarchar(36), newid()) select @temp_copy = @file_dir + @guid_name + '.tmp' -- copy file select @cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '" "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default + '"' exec @retcode = master.dbo.xp_cmdshell @cmd, NO_OUTPUT if @@error <> 0 or @retcode <> 0 begin raiserror(21248, 16, -1, @filename) select @retcode = 1 goto Cleanup end exec @retcode = dbo.sp_MSget_file_existence @temp_copy, @exists output if @@error <> 0 or @retcode <> 0 begin select @retcode = 1 goto Cleanup end if @exists = 0 begin raiserror(21247, 16, -1, @temp_copy) select @retcode = 1 goto Cleanup end select @copy_created = 1 -- decompress exec @retcode = master.dbo.xp_unpackcab @cabfilename = @temp_copy, @destination_folder = @file_dir, @verbose_level = 0, @destination_file = @file_name, @suppress_messages = 1 if @@error <> 0 begin select @retcode = 1 goto Cleanup end if @retcode in (1030,1029,2005) begin raiserror(20609, 16, -1, @filename) select @retcode = 1 goto Cleanup end else if @retcode <> 0 -- re-issue the command to get errors begin exec @retcode = master.dbo.xp_unpackcab @cabfilename = @temp_copy, @destination_folder = @file_dir, @verbose_level = 0, @destination_file = @file_name, @suppress_messages = 0 select @retcode = 1 goto Cleanup end -- Attach exec @retcode = dbo.sp_attach_single_file_db @dbname = @dbname, @physname = @filename if @retcode<>0 or @@error<>0 begin raiserror(21248, 16, -1, @filename) select @retcode = 1 goto Cleanup end -- Prepare the database for detach. 2 things will be done -- 1. Set a flag to indicate that this is a prepare sub db for detach -- 2. For merge, create table to store sysservers info for later fixing up after attach select @cmd = quotename(@dbname) + '.dbo.sp_MSrestore_sub' exec @retcode = @cmd @subscriber_security_mode = @subscriber_security_mode, @subscriber_login = @subscriber_login, @subscriber_password = @subscriber_password if @retcode<>0 or @@error<>0 begin select @retcode = 1 goto Cleanup end Cleanup: if @retcode <> 0 begin -- The files will be deleted if some thing failed. if exists (select * from master..sysdatabases where name = @dbname collate database_default) begin select @cmd = 'drop database ' + quotename(@dbname) exec (@cmd) end end if @temp_copy is not null begin -- Restore the original file, ignore errors if @retcode <> 0 and @copy_created = 1 begin select @cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default + '" "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"' exec master.dbo.xp_cmdshell @cmd, NO_OUTPUT end -- Delete the temp file. select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default+ '"' EXEC master..xp_cmdshell @cmd, NO_OUTPUT end return @retcode go EXEC dbo.sp_MS_marksystemobject sp_attachsubscription GO grant execute on dbo.sp_attachsubscription to public go -------------------------------------------------------------------------------- --. sp_browsesnapshotfolder -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_browsesnapshotfolder') drop procedure sp_browsesnapshotfolder go raiserror('Creating procedure sp_browsesnapshotfolder', 0,1) go CREATE PROCEDURE sp_browsesnapshotfolder ( @publication sysname, @subscriber sysname = NULL, @subscriber_db sysname = NULL ) AS BEGIN SET NOCOUNT ON DECLARE @retcode INT DECLARE @publisher sysname DECLARE @publisher_db sysname DECLARE @distributor sysname DECLARE @distributiondb sysname DECLARE @distproc nvarchar(300) DECLARE @article_id INT SELECT @retcode = 0 SELECT @publisher = NULL SELECT @publisher_db = DB_NAME() SELECT @distributor = NULL SELECT @distributiondb = NULL SELECT @article_id = NULL EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) -- Either both of @subscriber and @subscriber_db are NULL or -- both of them have to be non-null IF ((@subscriber IS NULL OR @subscriber = N'') AND @subscriber_db IS NOT NULL AND @subscriber_db <> N'') OR ((@subscriber_db IS NULL OR @subscriber_db = N'') AND @subscriber IS NOT NULL AND @subscriber <> N'') BEGIN RAISERROR(21148, 16, -1) END IF EXISTS (SELECT * FROM sysobjects WHERE name = N'syspublications') AND EXISTS (SELECT * FROM sysobjects WHERE name = N'sysextendedarticlesview') BEGIN SELECT @publisher = @@SERVERNAME -- Get the smallest article id for the publication since -- method for identifying a publication is not readily available -- on the distributor SELECT @article_id = MIN(artid) FROM sysextendedarticlesview sa INNER JOIN syspublications sp ON sa.pubid = sp.pubid WHERE sp.name = @publication IF @article_id IS NULL BEGIN RAISERROR(20026, 16, -1, @publication) END EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distributiondb OUTPUT IF @retcode <> 0 RETURN @retcode SELECT @distributor = RTRIM(@distributor) IF LOWER(@@SERVERNAME) <> LOWER(@distributor) BEGIN SELECT @distproc = @distributor + '.' + @distributiondb + '.dbo.sp_MSbrowsesnapshotfolder' END ELSE BEGIN SELECT @distproc = @distributiondb + '.dbo.sp_MSbrowsesnapshotfolder' END EXECUTE @retcode = @distproc @publisher = @publisher, @publisher_db = @publisher_db, @article_id = @article_id, @subscriber = @subscriber, @subscriber_db = @subscriber_db RETURN @retcode END ELSE BEGIN RAISERROR(21149, 16, -1, @publisher_db) RETURN 1 END END GO EXEC dbo.sp_MS_marksystemobject sp_browsesnapshotfolder go grant execute on dbo.sp_browsesnapshotfolder to public go -------------------------------------------------------------------------------- --. sp_copysnapshot -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_copysnapshot') drop procedure sp_copysnapshot go raiserror('Creating procedure sp_copysnapshot', 0,1) go CREATE PROCEDURE sp_copysnapshot ( @publication sysname, @destination_folder nvarchar(255), @subscriber sysname = NULL, @subscriber_db sysname = NULL ) AS BEGIN SET NOCOUNT ON DECLARE @retcode int DECLARE @source_folder nvarchar(255) SELECT @retcode = 0 -- security check, db_owner EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) CREATE TABLE #snapshot_folders ( id int identity, snapshot_folder nvarchar(255) collate database_default ) IF @@ERROR <> 0 BEGIN RETURN 1 END INSERT INTO #snapshot_folders EXEC @retcode = sp_browsesnapshotfolder @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db IF @retcode <> 0 OR @@ERROR <> 0 BEGIN GOTO Failure END SELECT @source_folder = (select top 1 snapshot_folder FROM #snapshot_folders ORDER BY id) IF @@ERROR <> 0 BEGIN GOTO Failure END SET ROWCOUNT 0 EXEC @retcode = sp_MScopysnapshot @source_folder, @destination_folder IF @retcode <> 0 OR @@ERROR <> 0 BEGIN GOTO Failure END DROP TABLE #snapshot_folders RETURN 0 Failure: SET ROWCOUNT 0 DROP TABLE #snapshot_folders RETURN 1 END GO EXEC dbo.sp_MS_marksystemobject sp_copysnapshot go grant execute on dbo.sp_copysnapshot to public go -------------------------------------------------------------------------------- --. sp_getagentoffloadinfo -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_getagentoffloadinfo') drop procedure sp_getagentoffloadinfo go print '' print 'Creating procedure sp_getagentoffloadinfo' go CREATE PROCEDURE sp_getagentoffloadinfo ( @job_id VARBINARY(16) ) AS SET NOCOUNT ON DECLARE @retcode INT DECLARE @distributor sysname DECLARE @distributiondb sysname DECLARE @distproc NVARCHAR(300) SELECT @retcode = 0 SELECT @distributor = NULL SELECT @distributiondb = NULL -- security check, db_owner EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distributiondb OUTPUT IF @retcode <> 0 RETURN @retcode SELECT @distributor = RTRIM(@distributor) SELECT @distproc = @distributor + '.' + @distributiondb + '.dbo.sp_MSgetagentoffloadinfo' EXECUTE @retcode = @distproc @job_id = @job_id RETURN @retcode GO EXEC dbo.sp_MS_marksystemobject sp_getagentoffloadinfo GO grant execute on sp_getagentoffloadinfo to public go -------------------------------------------------------------------------------- --. System objects (replcom.sql) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --. sp_adddistributiondb -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_adddistributiondb') drop procedure sp_adddistributiondb go raiserror('Creating procedure sp_adddistributiondb', 0,1) go CREATE PROCEDURE sp_adddistributiondb ( @database sysname, @data_folder nvarchar(255) = NULL, @data_file nvarchar(255) = NULL, /* physical file name */ @data_file_size int = 2, /* Default: 2MB */ @log_folder nvarchar(255) = NULL, @log_file nvarchar(255) = NULL, /* physical file name */ @log_file_size int = 0, @min_distretention int = 0, /* min distribution retention period in hours */ @max_distretention int = 72, /* max distribution retention period in hours */ @history_retention int = 48, /* history retention period in hours */ @security_mode int = 0, /* distributor login security 0 standard 1 integrated */ @login sysname = 'sa', /* standard login name */ @password sysname = NULL, /* standard login password */ @createmode int = 0, /* 0: use create db for attach (recommended), 1: create db or use existing but no attach (this is the old way), 2: create for instdist and detach only */ @from_scripting bit = 0 ) AS SET NOCOUNT ON /* ** Declarations. */ DECLARE @data_path nvarchar(512) DECLARE @log_path nvarchar(512) DECLARE @data_path_quoted_for_copy nvarchar(512) DECLARE @log_path_quoted_for_copy nvarchar(512) DECLARE @logical_data_file nvarchar(255) DECLARE @logical_log_file nvarchar(255) DECLARE @canneddbdata_file nvarchar(255) DECLARE @canneddblog_file nvarchar(255) DECLARE @filecopy_cmd nvarchar(255) DECLARE @file_exists bit DECLARE @data_file_preexists int DECLARE @log_file_preexists int DECLARE @osql_path nvarchar(260) DECLARE @osql_cmd nvarchar(1000) DECLARE @osql_for_nt int DECLARE @devnum int --DECLARE @num_pages int DECLARE @retcode int DECLARE @reg_key nvarchar(255) DECLARE @agentname nvarchar(100) DECLARE @command nvarchar (2048) DECLARE @distbit int DECLARE @install_path nvarchar(255) DECLARE @mssql_data_path nvarchar(255) DECLARE @on_clause nvarchar(512) DECLARE @logon_clause nvarchar(512) DECLARE @distproc nvarchar(255) DECLARE @major_version int DECLARE @db_exists bit DECLARE @trunc_log_bit int DECLARE @description nvarchar(100) DECLARE @category_name sysname DECLARE @createmode_attach int DECLARE @createmode_noattach int DECLARE @createmode_fordetach int --DECLARE @filegrowth nvarchar(10) DECLARE @data_file_size_str nvarchar(10) DECLARE @log_file_size_str nvarchar(10) DECLARE @platform_nt binary --DECLARE @max_datafile_size int --DECLARE @max_logfile_size int IF @password = N'' select @password = NULL select @platform_nt = 0x1 --select @filegrowth = N'512KB' -- on error, delete the data and log files only if they didn't pre-exist. -- by default, assume they pre-exist. select @data_file_preexists = 1 select @log_file_preexists = 1 select @file_exists = 0 if (@data_file_size IS NULL) or (@data_file_size = 0) select @data_file_size_str = N'512KB' else select @data_file_size_str = convert(nvarchar(10), @data_file_size) if (@log_file_size IS NULL) or (@log_file_size = 0) select @log_file_size_str = N'512KB' else select @log_file_size_str = convert(nvarchar(10), @log_file_size) --if (@data_file_size > 16) -- select @max_datafile_size = @data_file_size --else -- select @max_datafile_size = 16 --if (@log_file_size > 16) -- select @max_logfile_size = @log_file_size --else -- select @max_logfile_size = 16 select @createmode_attach = 0, @createmode_noattach = 1, @createmode_fordetach = 2 SELECT @trunc_log_bit = 8 SELECT @distbit = 16 if (@createmode <> @createmode_fordetach) begin /* ** Check if replication components are installed on this server */ exec @retcode = dbo.sp_MS_replication_installed if (@retcode <> 1) begin return (1) end /* ** Check for invalid security modes */ IF @security_mode < 0 OR @security_mode > 1 BEGIN RAISERROR(14109, 16, -1) RETURN (1) END IF ( ( @platform_nt != platform() & @platform_nt ) and @security_mode = 1) BEGIN RAISERROR(21038, 16, -1) RETURN (1) END /* ** Check for invalid retention values */ IF @min_distretention < 0 OR @max_distretention < 0 BEGIN RAISERROR(14106, 16, -1) RETURN (1) END IF @min_distretention > @max_distretention BEGIN RAISERROR(14107, 16, -1) RETURN (1) END /* ** Check to make sure this is a distributor */ IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default AND srvstatus & 8 <> 0) BEGIN RAISERROR (14114, 16, -1, @@SERVERNAME) RETURN(1) END /* ** Check if database is already configured as a distributor database */ IF EXISTS (SELECT * FROM msdb..MSdistributiondbs WHERE name = @database collate database_default) BEGIN RAISERROR (14119, 16, -1, @database) RETURN(1) END end /* ** Get path to osql client (TOOLS) directory */ EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT IF ( @retcode <> 0 ) or ( @@ERROR <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' ) BEGIN GOTO UNDO END /* ** Get path to version specific INSTALL directory */ exec @retcode = master.dbo.sp_MSget_setup_paths @sql_path = @install_path output, @data_path = @mssql_data_path output IF @retcode <> 0 or @install_path is NULL or @install_path='' or @mssql_data_path = '' BEGIN GOTO UNDO END IF @data_folder IS NULL or @data_folder = '' select @data_folder = @mssql_data_path + '\DATA' IF @log_folder IS NULL or @log_folder = '' select @log_folder = @mssql_data_path + '\DATA' IF @data_file IS NULL SELECT @data_file = @database + '.MDF' IF @log_file IS NULL SELECT @log_file = @database + '.LDF' if substring(@data_folder, len(@data_folder), 1) = '\' select @data_folder = substring (@data_folder, 1, len(@data_folder) -1) if substring(@log_folder, len(@log_folder), 1) = '\' select @log_folder = substring (@log_folder, 1, len(@log_folder) -1) SELECT @data_path = @data_folder + '\' + @data_file SELECT @log_path = @log_folder + '\' + @log_file SELECT @data_path_quoted_for_copy = '"' + fn_escapecmdshellsymbolsremovequotes(@data_folder) collate database_default + '\' + fn_escapecmdshellsymbolsremovequotes(@data_file) collate database_default + '"' SELECT @log_path_quoted_for_copy = '"' + fn_escapecmdshellsymbolsremovequotes(@log_folder) collate database_default + '\' + fn_escapecmdshellsymbolsremovequotes(@log_file) collate database_default + '"' select @logical_data_file = @database /* ** Truncate the logical log file name back to 128 characters ** long so the 'CREATE DATABASE' statement won't complain. */ /* LEN(@logical_log_file) = LEN(@database) + LEN('_log') and LEN(@logical_log_file) <= 128 implies LEN(@database) <=124 */ IF (LEN(@database) > 124) SELECT @logical_log_file = SUBSTRING(@database, 1, 124) + '_log' ELSE SELECT @logical_log_file = @database + '_log' if (@createmode = @createmode_attach) begin select @canneddbdata_file = @mssql_data_path + '\DATA\DISTMDL.MDF' select @canneddblog_file = @mssql_data_path + '\DATA\DISTMDL.LDF' exec dbo.sp_MSget_file_existence @canneddbdata_file, @file_exists OUTPUT if (@file_exists = 0) begin /* Fallback to mode where instdist.sql needs to be run */ select @createmode = @createmode_noattach end exec dbo.sp_MSget_file_existence @canneddblog_file, @file_exists OUTPUT if (@file_exists = 0) begin /* Fallback to mode where instdist.sql needs to be run */ select @createmode = @createmode_noattach end end /* ** Create the distributor database if it does not exist */ IF NOT EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) AND (@createmode <> @createmode_attach) BEGIN -- Note: Use system's default file growth. IF @logical_data_file IS NOT NULL AND NOT EXISTS (SELECT * FROM master..sysdevices WHERE name = @logical_data_file collate database_default) BEGIN SELECT @on_clause = ' ON (NAME =''' + @logical_data_file + ''',FILENAME=''' + REPLACE( @data_path, '''', '''''' ) + ''', SIZE=' + @data_file_size_str + ', MAXSIZE = UNLIMITED)' END IF @logical_log_file IS NOT NULL AND NOT EXISTS (SELECT * FROM master..sysdevices WHERE name = @logical_log_file collate database_default) BEGIN SELECT @logon_clause = ' LOG ON (NAME =''' + @logical_log_file + ''',FILENAME=''' + REPLACE( @log_path, '''', '''''' ) + ''', SIZE=' + @log_file_size_str + ', MAXSIZE= UNLIMITED)' END /* ** Create distributor database */ SELECT @command = 'USE master CREATE DATABASE ' + QUOTENAME(@database) + + isnull(@on_clause, ' ') + isnull(@logon_clause, ' ') EXEC (@command) IF @@ERROR <> 0 RETURN (1) SELECT @db_exists = 0 END ELSE IF NOT EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) AND (@createmode = @createmode_attach) BEGIN /* DO THE CREATE DATABASE FOR ATTACH STUFF */ exec dbo.sp_MSget_file_existence @data_path, @data_file_preexists OUTPUT if (@data_file_preexists = 1) begin raiserror(5170, 16, -1, @data_path) return 1 end SELECT @on_clause = ' ON (NAME = ''' + @logical_data_file + ''', FILENAME=''' + REPLACE( @data_path, '''', '''''' ) + ''')' exec dbo.sp_MSget_file_existence @log_path, @log_file_preexists OUTPUT if (@log_file_preexists = 1) begin raiserror(5170, 16, -1, @log_path) return 1 end SELECT @logon_clause = ' LOG ON (NAME = ''' + @logical_log_file + ''', FILENAME=''' + REPLACE( @log_path, '''', '''''' ) + ''')' select @filecopy_cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@canneddbdata_file) collate database_default + '" ' + @data_path_quoted_for_copy EXEC @retcode = master..xp_cmdshell @filecopy_cmd, NO_OUTPUT IF @retcode <> 0 OR @@ERROR <> 0 BEGIN RAISERROR (14113, 16, -1, @filecopy_cmd, 'instdist.out') return (1) END select @filecopy_cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@canneddblog_file) collate database_default + '" ' + @log_path_quoted_for_copy EXEC @retcode = master..xp_cmdshell @filecopy_cmd, NO_OUTPUT IF @retcode <> 0 OR @@ERROR <> 0 BEGIN RAISERROR (14113, 16, -1, @filecopy_cmd, 'instdist.out') return (1) END /* ** Create distributor database */ SELECT @command = 'USE master CREATE DATABASE ' + QUOTENAME(@database) + + @on_clause + @logon_clause + ' FOR ATTACH' EXEC (@command) IF @@ERROR <> 0 begin RETURN (1) end dbcc dbreindexall(@database, 240) with no_infomsgs SELECT @db_exists = 0 END ELSE BEGIN SELECT @db_exists = 1 END -- Must make the dist db owned by sa so that the sps in it can select from -- security cache tables in tempdb by owership chain rule. declare @retcode2 int select @retcode2 = 0 select @distproc = QUOTENAME(@database) + '.dbo.sp_executesql' SELECT @command = -- If the db is created by sa or from attach, sa is dbo already. -- sp_changedbowner will fail is the new owner is an user in the db already. ' if not exists (select * from sysusers where sid = 0x01) ' + ' exec @retcode2 = dbo.sp_changedbowner ''sa''' EXEC @retcode = @distproc @command, N'@retcode2 int output', @retcode2 output IF @retcode <> 0 or @retcode2 <> 0 or @@ERROR <> 0 BEGIN GOTO UNDO END /* Set the database option truncate log on checkpoint & turn off autoclose which is default of win9x*/ IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = @database collate database_default AND (status & @trunc_log_bit) = 0 ) -- if its not already marked BEGIN EXEC @retcode = dbo.sp_dboption @database, 'trunc. log on chkpt.', 'true' IF @retcode <> 0 OR @@ERROR <> 0 BEGIN GOTO UNDO END END EXEC @retcode = dbo.sp_dboption @database, 'autoclose', 'false' IF @retcode <> 0 OR @@ERROR <> 0 BEGIN GOTO UNDO END /* ** ** Update sysdatabase category bit ** This is to prevent user from dropping the database. **/ if (@createmode <> @createmode_fordetach) begin UPDATE master..sysdatabases SET category = category | @distbit WHERE name = @database collate database_default IF @@ERROR <> 0 BEGIN GOTO UNDO END end /* ** Install instdist.sql */ if (@createmode <> @createmode_attach) OR (@db_exists = 1) begin if (( platform() & @platform_nt = @platform_nt )) select @osql_for_nt = 1 else select @osql_for_nt = 0 -- Always use integrated security on WINNT since @login passed-in is for remote -- subscriber and may not have enough privilege to apply the script IF (@security_mode = 1 or @osql_for_nt = 1) AND NOT (@security_mode = 0 AND @createmode = 2) BEGIN SELECT @osql_cmd = '" "' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E ' if serverproperty('instancename') is not null SELECT @osql_cmd = @osql_cmd + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" ' END ELSE BEGIN -- cannot specify -S w/ -E for local execution, SID does not map if (@osql_for_nt = 1) SELECT @osql_cmd = '" "' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" ' else SELECT @osql_cmd = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" ' END select @osql_cmd = @osql_cmd + '-l60 -t60 ' -- We must use -b option to make osql return error code !! SELECT @osql_cmd = @osql_cmd + ' -d"' + fn_escapecmdshellsymbols(@database) collate database_default + '" -b ' + ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.sql"' + ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.out"' if (@osql_for_nt = 1) BEGIN SELECT @osql_cmd = @osql_cmd + ' "' END EXEC @retcode = master..xp_cmdshell @osql_cmd IF @retcode <> 0 OR @@ERROR <> 0 BEGIN RAISERROR (14113, 16, -1, @osql_cmd, 'instdist.out') GOTO UNDO END end if (@createmode <> @createmode_fordetach) begin /* Set db_existed bit in MSrepl_version */ IF @db_exists = 1 BEGIN SELECT @distproc = 'UPDATE ' + @database + '..MSrepl_version SET db_existed = 0x1' EXEC(@distproc) IF @@ERROR <> 0 BEGIN GOTO UNDO END END DELETE msdb.dbo.MSdistributiondbs WHERE name = @database collate database_default IF @@ERROR <> 0 BEGIN GOTO UNDO END INSERT INTO msdb.dbo.MSdistributiondbs VALUES ( @database, @min_distretention, @max_distretention, @history_retention ) IF @@ERROR <> 0 BEGIN GOTO UNDO END -- This login need db_owner priviledge to call sps in distribution db declare @distributor_login sysname select @distributor_login = 'distributor_admin' select @command = quotename(@database) + '.dbo.sp_MSrepl_dbrole' exec @retcode = @command 'db_owner', @distributor_login, 'add' IF @@error <> 0 OR @retcode <> 0 GOTO UNDO if @from_scripting = 0 begin /* ** Create the history cleanup agent. */ SELECT @agentname = formatmessage (20567, @database) SELECT @command = 'EXEC dbo.sp_MShistory_cleanup @history_retention = ' + CONVERT(nvarchar(12), @history_retention) IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))) BEGIN EXEC @retcode = msdb.dbo.sp_delete_job @job_name = @agentname IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO UNDO END END set @description = formatmessage(20535) -- Get History Cleanup category name (assumes category_id = 12) select @category_name = name FROM msdb.dbo.syscategories where category_id = 12 EXECUTE @retcode = dbo.sp_MSadd_repl_job @agentname, @subsystem = 'TSQL', @server = @@SERVERNAME, @databasename = @database, @description = @description, @freqtype = 4, @freqsubtype = 4, @freqsubinterval = 10, /* Number of minutes between runs */ @command = @command, @enabled = 1, @retryattempts = 0, @loghistcompletionlevel = 0, @category_name = @category_name IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO UNDO END /* ** Create the distribution cleanup agent. */ SELECT @agentname = formatmessage (20568, @database) SELECT @command = 'EXEC dbo.sp_MSdistribution_cleanup @min_distretention = ' + CONVERT(nvarchar(12), @min_distretention) + ', @max_distretention = ' + CONVERT(nvarchar(12), @max_distretention) IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))) BEGIN EXEC @retcode = msdb.dbo.sp_delete_job @job_name = @agentname IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO UNDO END END set @description = formatmessage(20541) -- Get Distribution Cleanup category name (assumes category_id = 11) select @category_name = name FROM msdb.dbo.syscategories where category_id = 11 EXECUTE @retcode = msdb.dbo.sp_MSadd_repl_job @agentname, @subsystem = 'TSQL', @server = @@SERVERNAME, @databasename = @database, @description = @description, @freqtype = 4, @freqsubtype = 4, @freqsubinterval = 10, /* Number of minutes between runs */ @command = @command, @retryattempts = 0, @enabled = 0, @loghistcompletionlevel = 0, @category_name = @category_name, -- Start and end time is 5 min off from the history cleanup, which use the default. @activestarttimeofday = 000500, @activeendtimeofday = 000459 IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO UNDO end end end else begin /*detach */ dbcc detachdb(@database) end RETURN(0) UNDO: IF @db_exists = 0 EXECUTE dbo.sp_dropdistributiondb @database /* Need to do it since sp_dropdistributiondb will fail in some cases */ UPDATE master..sysdatabases SET category = category & ~@distbit WHERE name = @database collate database_default DELETE msdb.dbo.MSdistributiondbs where name = @database collate database_default /* drop the database and ignore error */ IF @db_exists = 0 AND EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) BEGIN SELECT @command = 'USE master DROP DATABASE ' + QUOTENAME(@database) EXEC (@command) END if (@createmode = @createmode_attach) begin if (@data_file_preexists = 0) begin select @command = 'del ' + @data_path_quoted_for_copy exec master..xp_cmdshell @command --ignore errors end if (@log_file_preexists = 0) begin select @command = 'del ' + @log_path_quoted_for_copy exec master..xp_cmdshell @command --ignore errors end end RETURN(1) GO -------------------------------------------------------------------------------- --. sp_adddistpublisher -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_adddistpublisher') drop procedure sp_adddistpublisher go raiserror('Creating procedure sp_adddistpublisher', 0,1) go CREATE PROCEDURE sp_adddistpublisher ( @publisher sysname, /* publisher server name */ @distribution_db sysname, @security_mode int = NULL, @login sysname = 'sa', @password sysname = NULL, @working_directory nvarchar(255), @trusted nvarchar(5) = NULL, @encrypted_password bit = 0, @thirdparty_flag bit = 0 ) AS SET NOCOUNT ON /* ** Declarations. */ DECLARE @retcode int DECLARE @reg_key nvarchar(255) DECLARE @distbit int DECLARE @active_value int DECLARE @server_added bit DECLARE @proc nvarchar(255) declare @fExists int declare @command nvarchar(255) declare @trusted_id bit declare @platform_nt binary declare @qv_replication varchar(10) declare @qv_replication_unlimited integer declare @qv_value_replication integer declare @enc_password nvarchar(524) select @platform_nt = 0x1 select @qv_replication = '2745196162', @qv_replication_unlimited = 0 SELECT @distbit = 16 SELECT @server_added = 0 /* ** Check if replication components are installed on this server */ exec @retcode = dbo.sp_MS_replication_installed if (@retcode <> 1) begin return (1) end IF @working_directory IS NULL or ltrim(rtrim(@working_directory)) = '' BEGIN RAISERROR (14043, 16, -1, '@working_directory') return (1) END /* ** Parameter Check: @publisher. ** Check to make sure that the publisher is not NULL and that it ** conforms to the rules for identifiers. */ IF @publisher IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher') return (1) END EXECUTE @retcode = dbo.sp_validname @publisher IF @@ERROR <> 0 OR @retcode <> 0 return (1) IF @password = N'' select @password = NULL /* On REPLICATION_LIMITED server, only local publisher is supported. * Note: The login and password registered for local publisher will be used for * local agents to login to distributor, thus local publisher has to be installed first. * We choose not to support remote dist publshers on REPLICATION_LIMITED server altogether. * On NT, local agents will always use integrated security to log into * distributor * Today, REPLICATION_LIMITED means desktop but we check specific sku entry just in case */ exec @qv_value_replication = master.dbo.sp_MSinstance_qv @qv_replication if ( @qv_value_replication != @qv_replication_unlimited ) and ( UPPER(@publisher) <> UPPER(@@servername) ) begin -- remote dist publisher is not supported on this server version raiserror(21041,16,-1) return (1) end -- Set default security IF @security_mode IS NULL BEGIN IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( platform() & @platform_nt = @platform_nt ) ) SELECT @security_mode = 1 ELSE SELECT @security_mode = 0 END /* ** Check for invalid security mode */ IF @security_mode < 0 OR @security_mode > 1 BEGIN RAISERROR(14109, 16, -1) return (1) END IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( @platform_nt != platform() & @platform_nt ) and @security_mode = 1) BEGIN RAISERROR(21038, 16, -1) RETURN (1) END -- Encrypt the password select @enc_password = @password IF @encrypted_password = 0 BEGIN EXEC @retcode = master.dbo.xp_repl_encrypt @enc_password OUTPUT IF @@error <> 0 OR @retcode <> 0 return 1 END -- Validate the working directory -- Remove heading and trailing spaces select @working_directory = RTRIM(LTRIM(@working_directory)) -- if the last char is '\', remove it. if substring(@working_directory, len(@working_directory),1) = '\' select @working_directory = substring(@working_directory, 1, len(@working_directory)-1) -- Don't do validation if it is a UNC path due to security problem. -- If the server is started as a service using local system account, we -- don't have access to the UNC path. if substring(@working_directory, 1,2) <> '\\' begin select @command = 'dir "' + fn_escapecmdshellsymbolsremovequotes(@working_directory) collate database_default + '"' exec @retcode = master..xp_cmdshell @command, 'no_output' if @@error <> 0 return (1) if @retcode <> 0 begin raiserror (21037, 16, -1, @working_directory) return (1) end end /* ** Parameter Check: @trusted */ if @trusted is null begin if UPPER(@publisher) = UPPER(@@servername) select @trusted = 'false' else select @trusted = 'true' end IF LOWER(@trusted collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@trusted') RETURN (1) END IF LOWER(@trusted collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @trusted_id = 1 ELSE SELECT @trusted_id = 0 /* ** Check to make sure this is a distributor */ IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default AND srvstatus & 8 <> 0) BEGIN RAISERROR (14114, 16, -1, @@SERVERNAME) return (1) END /* ** Check if database is configured as a distributor database */ IF NOT EXISTS (SELECT * FROM msdb..MSdistributiondbs WHERE name = @distribution_db collate database_default) BEGIN RAISERROR (14117, 16, -1, @distribution_db) return (1) END /* Check if publisher is already defined. */ IF EXISTS (SELECT * FROM msdb..MSdistpublishers WHERE UPPER(name) = UPPER(@publisher) collate database_default) BEGIN RAISERROR (14074, 16, -1, @publisher) RETURN (1) END IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(srvname) = UPPER(@publisher) collate database_default) /* Add the server if it does not exist. */ BEGIN EXECUTE @retcode = dbo.sp_addserver @publisher IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) GOTO UNDO END SELECT @server_added = 1 END ELSE BEGIN SELECT @publisher = fn_getpersistedservernamecasevariation(@publisher) collate database_default END /* ** Set the Active value. ** If the @publisher is local, set it to true. ** Otherwise, set it to false */ IF UPPER(@publisher) = UPPER(@@SERVERNAME) SELECT @active_value = 1 ELSE SELECT @active_value = 0 DELETE msdb.dbo.MSdistpublishers where UPPER(name) = UPPER(@publisher) collate database_default IF @@ERROR <> 0 BEGIN GOTO UNDO END INSERT INTO msdb.dbo.MSdistpublishers VALUES ( @publisher, @distribution_db, @working_directory, @security_mode, @login, @enc_password, @active_value, @trusted_id, @thirdparty_flag) IF @@ERROR <> 0 BEGIN GOTO UNDO END -- Add distributor_admin to distribution_admin non trusted mapping exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, null, 'distributor_admin' if( @fExists = 0 ) BEGIN EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'distributor_admin', 'distributor_admin' IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) GOTO UNDO END END -- For 6x publisher, we still need the trusted sa to sa. -- For 6x publisher upgrading to 7.0, distributor_admin to distributor_admin need to be trusted. -- add remotelogin of SA if it doesn't already exist -- If there's a mapping for remote login sa already, we cannot map it to distributor_admin -- this is the case of server upgraded from 6.5. exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, null, 'sa' if( @fExists = 0 ) BEGIN EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'distributor_admin', 'sa' IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) GOTO UNDO END END if @trusted_id = 1 begin exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa' if( @fExists = 1 ) BEGIN EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, true IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) GOTO UNDO END END EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'distributor_admin', trusted, true IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) GOTO UNDO END END /* Add remotelogin enabling the 'probe' of the publisher to ** RPC for distribution counter information. */ /* SECURITY ******************************** IF NOT EXISTS (SELECT * FROM master..sysremotelogins srl, master..sysservers ss WHERE UPPER(ss.srvname) = UPPER(@publisher) collate database_default AND srl.remoteserverid = ss.srvid AND srl.remoteusername = 'probe' AND srl.suid = 10) -- 'probe' exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'probe', 'probe' if (@fExists = 0) BEGIN EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'probe', 'probe' IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) GOTO UNDO END END *********************************/ RETURN(0) UNDO: -- If the server is marked, drop it IF EXISTS (SELECT * FROM msdb..MSdistpublishers WHERE UPPER(name) = UPPER(@publisher) collate database_default) EXEC dbo.sp_dropdistpublisher @publisher IF @server_added = 1 EXEC dbo.sp_dropserver @publisher RETURN(1) GO -------------------------------------------------------------------------------- --. sp_changedistpublisher -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_changedistpublisher') drop procedure sp_changedistpublisher go raiserror('Creating procedure sp_changedistpublisher', 0,1) go CREATE PROCEDURE sp_changedistpublisher ( @publisher sysname, @property sysname = NULL, /* The property to change */ @value nvarchar(255) = NULL /* The new property value */ ) AS SET NOCOUNT ON /* ** Declarations. */ DECLARE @retcode int DECLARE @new_database sysname DECLARE @new_security_mode int DECLARE @new_login sysname DECLARE @new_password nvarchar(524) DECLARE @distbit int DECLARE @new_active int DECLARE @new_trusted bit DECLARE @command nvarchar(255) declare @distribdb sysname DECLARE @platform_nt binary SELECT @platform_nt = 0x1 SELECT @distbit = 16 /* ** Parameter Check: @property. ** If the @property parameter is NULL, print the options. */ IF @property IS NULL BEGIN CREATE TABLE #tab1 (properties sysname collate database_default not null) INSERT INTO #tab1 VALUES ('distribution_db') INSERT INTO #tab1 VALUES ('working_directory') INSERT INTO #tab1 VALUES ('security_mode') INSERT INTO #tab1 VALUES ('login') INSERT INTO #tab1 VALUES ('password') INSERT INTO #tab1 VALUES ('active') INSERT INTO #tab1 VALUES ('trusted') SELECT * FROM #tab1 RETURN (0) END /* ** Parameter Check: @property. ** Check to make sure that @property is a valid property in ** msdb.dbo.MSdistpublishers. */ IF @property IS NULL OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('distribution_db', 'working_directory', 'security_mode', 'login', 'password', 'active', 'trusted') BEGIN RAISERROR (14115, 16, -1, '''distribution_db'', ''working_directory'', ''security_mode'', ''login'', ''password'', ''active'', or ''trusted''') RETURN (1) END /* ** Check to make sure this is a distributor */ IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default AND srvstatus & 8 <> 0) BEGIN RAISERROR (14114, 16, -1, @@SERVERNAME) RETURN(1) END -- Get the distribution db name. select @distribdb = distribution_db from msdb..MSdistpublishers where UPPER(name) = UPPER(@publisher) collate database_default /* ** Change the property. */ IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distribution_db' BEGIN IF @value IS NULL BEGIN RAISERROR (14043, 16, -1, '@value') RETURN (1) END IF @value <> @distribdb and EXISTS (SELECT * FROM msdb.dbo.MSdistpublishers WHERE UPPER(name) = UPPER(@publisher) collate database_default and active = 1) BEGIN RAISERROR (21046, 16, -1) RETURN (1) END /* ** Check if database is configured as a distributor database */ IF NOT EXISTS (SELECT * FROM master..sysdatabases WHERE name = @value collate database_default AND category & @distbit <> 0) BEGIN RAISERROR (14117, 16, -1, @new_database) RETURN(1) END UPDATE msdb..MSdistpublishers SET distribution_db = @value WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'working_directory' BEGIN IF @value IS NULL BEGIN RAISERROR (14043, 16, -1, '@value') RETURN (1) END -- Validate the working directory -- Remove heading and trailing spaces select @value = RTRIM(LTRIM(@value)) -- if the last char is '\', remove it. if substring(@value, len(@value),1) = '\' select @value = substring(@value, 1, len(@value)-1) -- Don't do validation if it is a UNC path due to security problem. -- If the server is started as a service using local system account, we -- don't have access to the UNC path. if substring(@value, 1,2) <> '\\' begin select @command = 'dir "' + fn_escapecmdshellsymbolsremovequotes(@value) collate database_default + N'"' exec @retcode = master..xp_cmdshell @command, 'no_output' if @@error <> 0 return 1 if @retcode <> 0 begin raiserror (21037, 16, -1, @value) return 1 end end UPDATE msdb..MSdistpublishers SET working_directory = @value WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'security_mode' BEGIN IF @value IS NULL BEGIN RAISERROR (14043, 16, -1, '@value') RETURN (1) END /* ** Set the SecurityMode registry key value */ SELECT @new_security_mode = CONVERT(int, @value) /* ** Check for invalid values */ IF @new_security_mode < 0 OR @new_security_mode > 1 BEGIN RAISERROR(14109, 16, -1) RETURN (1) END IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( @platform_nt != platform() & @platform_nt ) and @new_security_mode = 1) BEGIN RAISERROR(21038, 16, -1) RETURN (1) END UPDATE msdb..MSdistpublishers SET security_mode = @new_security_mode WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'login' BEGIN IF @value IS NULL BEGIN RAISERROR (14043, 16, -1, '@value') RETURN (1) END /* ** Set the Login registry key value */ SELECT @new_login = CONVERT(sysname, @value) UPDATE msdb..MSdistpublishers SET login = @new_login WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'password' BEGIN /* ** Set the Password registry key value */ SELECT @new_password = CONVERT(nvarchar(524), @value) -- Encrypt the password EXEC @retcode = master.dbo.xp_repl_encrypt @new_password OUTPUT IF @@error <> 0 OR @retcode <> 0 RETURN (1) UPDATE msdb..MSdistpublishers SET password = @new_password WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'active' BEGIN /* ** Check for a valid value. */ IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false') BEGIN RAISERROR (14137, 16, -1) RETURN (1) END IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true' begin -- Clean up the database in case of the remote publisher is reinstalling publishing. SELECT @command = @distribdb + '.dbo.sp_MSdistpublisher_cleanup' exec @retcode = @command @publisher if @retcode <> 0 or @@error <> 0 return 1 SELECT @new_active = 1 end ELSE BEGIN SELECT @new_active = 0 END /* ** Set the Active registry key value */ UPDATE msdb..MSdistpublishers SET active = @new_active WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'trusted' BEGIN /* ** Check for a valid value. */ IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false') BEGIN RAISERROR (14137, 16, -1) RETURN (1) END declare @fExists int IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true' begin SELECT @new_trusted = 1 exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa' if( @fExists = 1 ) BEGIN EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, true IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) RETURN (1) END END EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'distributor_admin', trusted, true IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) RETURN (1) END end ELSE BEGIN SELECT @new_trusted = 0 exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa' if( @fExists = 1 ) BEGIN EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, false IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) RETURN (1) END END EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'distributor_admin', trusted, 'false' IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14075, 16, -1) RETURN (1) END END /* ** Set the trusted property */ UPDATE msdb..MSdistpublishers SET trusted = @new_trusted WHERE UPPER(name) = UPPER(@publisher) collate database_default IF @@error <> 0 BEGIN RETURN (1) END END /* ** Return succeed. */ RAISERROR (21035, 10, -1, @property) DONE: RETURN (0) go -------------------------------------------------------------------------------- --. sp_MScopyscriptfile -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MScopyscriptfile') drop procedure sp_MScopyscriptfile go create proc sp_MScopyscriptfile ( @scriptfile nvarchar(4000), @cmd nvarchar(4000) OUTPUT ) as declare @directory nvarchar(4000) declare @filename nvarchar(1024) declare @subdirectory nvarchar(1024) declare @retcode int IF @scriptfile IS NULL BEGIN RAISERROR (14043, 16, -1, '@scriptfile') RETURN (1) END -- Create the directory on distributor to store script. exec sp_helpdistributor @directory=@directory OUTPUT select @subdirectory = convert(nvarchar(64), GetDate(), 121) select @subdirectory = replace(@subdirectory, N'-', N'') select @subdirectory = replace(@subdirectory, N' ', N'') select @subdirectory = replace(@subdirectory, N':', N'') select @subdirectory = replace(@subdirectory, N'.', N'') if(right(@directory, 1) = N'\') select @directory = @directory + @subdirectory else select @directory = @directory + N'\' + @subdirectory select @cmd = N'md "' + fn_escapecmdshellsymbolsremovequotes(@directory) collate database_default + '"' exec @retcode = master..xp_cmdshell @cmd, NO_OUTPUT if(@retcode <> 0) begin raiserror(21330, 16, -1, @cmd) return (1) end -- Copy script to distributor select @cmd = N'copy "' + fn_escapecmdshellsymbolsremovequotes(@scriptfile) collate database_default + N'" "' + fn_escapecmdshellsymbolsremovequotes(@directory) collate database_default + N'"' exec @retcode = master..xp_cmdshell @cmd, NO_OUTPUT if(@retcode <> 0) begin raiserror(21331, 16, -1, @cmd) return (1) end -- Prepare command, to be posted to log select @filename = right(@scriptfile, charindex(N'\', reverse(@scriptfile))) if(left(@filename, 1) = N'\') select @cmd = @directory + @filename else select @cmd = @directory + N'\' + @filename go exec sp_MS_marksystemobject sp_MScopyscriptfile go -------------------------------------------------------------------------------- --. sp_replproberemoteserver -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_replproberemoteserver') drop procedure sp_replproberemoteserver go raiserror('Creating procedure sp_replproberemoteserver', 0,1) go -- -- Name: sp_replproberemoteserver -- -- Description: This is a lightweight wrapper for calling xp_replproberremsrv -- with the added nicety of looking up the agent command line -- using the given jobid. This procedure supports two different -- modes of operation based on the @no_rpc parameter. If the -- @no_rpc parameter is 1, this procedure will not attempt to make -- rpc call to the Distributor. The local mode is mainly useful -- for verifying remote pull subscription agent. -- -- Parameters: @remoteservername sysname (mandatory) -- @agent_type nvarchar(16) (optional, default = null) -- @agent_jobid uniqueidentifier (optional default = null) -- @no_rpc bit (optional default = 0) -- -- Notes: If @job_id is null, only activation verification will be carried -- out. -- -- Security: Execute permission of this procedure is granted to public. -- Internal security check is performed inside this procedure to -- make sure that the caller is at least a db_owner of the current -- database. -- -- Result: 'probe_succeeded' 0 or 1 -- -- Returns: 0 - succeeded -- <> 0 - failed -- create procedure dbo.sp_replproberemoteserver ( @remoteservername sysname, @agent_type nvarchar(16) = null, @agent_jobid uniqueidentifier = null, @no_rpc bit = 0 ) as begin set nocount on declare @retcode int declare @commandline nvarchar(3200) declare @distributor sysname declare @distributiondb sysname declare @distproc nvarchar(255) declare @succeeded nvarchar(10) select @retcode = 0 select @commandline = null select @succeeded = null -- security check, db_owner -- Note that this proc can be called from either a publisher database or -- a subscriber database exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 return (1) if @agent_type is null begin select @agent_type = 'distribution' end -- @remoteservername cannot be null or empty select @remoteservername = rtrim(ltrim(@remoteservername)) if @remoteservername is null or @remoteservername = N'' begin raiserror(21263,16,-1,'@remoteservername') return 1 end -- @agent_type must be 'distribution' or 'merge' if @agent_type not in (N'distribution', N'merge') begin raiserror(21182,16,-1) return 1 end -- Get Distributor information if @no_rpc = 0 begin exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor output, @distribdb = @distributiondb output if @@error <> 0 or @retcode <> 0 return 1 end else begin select @distributor = @@servername end if upper(@@servername) <> upper(@distributor) begin select @distproc = ltrim(rtrim(@distributor)) + '.' + 'master.dbo.sp_replproberemoteserver' exec @retcode = @distproc @remoteservername, @agent_type, @agent_jobid, 1 return @retcode end else begin -- If the given @job_id is not null, try to get -- the agent command line if @agent_jobid is not null begin select @commandline = fn_replgetagentcommandlinefromjobid( @agent_type, @agent_jobid) collate database_default if @commandline is null begin raiserror(21361,6,-1, @agent_type) select 'probe_succeeded' = 0 return 1 end end exec @retcode = master.dbo.xp_replproberemsrv @remoteservername, @agent_type, @succeeded output, @commandline if lower(@succeeded collate SQL_Latin1_General_CP1_CS_AS) = N'true' select 'probe_succeeded' = 1 else select 'probe_succeeded' = 0 return @retcode end select 'probe_succeeded' = 0 return 1 end go exec sp_MS_marksystemobject sp_replproberemoteserver go grant execute on dbo.sp_replproberemoteserver to public go if exists (select * from sysobjects where type = 'X' and name = 'sp_replsetoriginator_internal' ) exec dbo.sp_dropextendedproc 'sp_replsetoriginator_internal' go sp_addextendedproc 'sp_replsetoriginator_internal', 'replsetoriginator extended procedure' go if exists (select * from sysobjects where type = 'X' and name = 'sp_replsetoriginator' ) exec dbo.sp_dropextendedproc 'sp_replsetoriginator' go if exists (select * from sysobjects where type = 'P' and name = 'sp_replsetoriginator' ) drop procedure sp_replsetoriginator go -- -- Name: -- sp_replsetoriginator -- -- Description: -- wrapper for sp_replsetoriginator_internal with DBO check -- -- Security: -- DBO only -- -- Returns: 0 : success -- 1 : failure -- -- Owner: -- qunguo -- -- raiserror('Creating procedure sp_replsetoriginator',0,1) go create proc sp_replsetoriginator ( @originator_srv sysname, @originator_db sysname ) as declare @retcode int /* ** Security Check, this proc is only called by distrib.exe, against sub db as DBO */ exec @retcode = dbo.sp_MSreplcheck_subscribe if @@ERROR <> 0 or @retcode <> 0 begin return(1) end exec @retcode = dbo.sp_replsetoriginator_internal @originator_srv, @originator_db if @@ERROR <> 0 or @retcode <> 0 begin return(1) end return 0 go exec sp_MS_marksystemobject sp_replsetoriginator go grant execute on dbo.sp_replsetoriginator to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_replsetoriginator_pal' ) drop procedure sp_replsetoriginator_pal go -- -- Name: -- sp_replsetoriginator_pal -- -- Description: -- wrapper for sp_replsetoriginator_internal with pull access check -- -- Security: -- DBO or PAL access -- -- Returns: 0 : success -- 1 : failure -- -- Owner: -- qunguo -- -- raiserror('Creating procedure sp_replsetoriginator_pal',0,1) go create proc sp_replsetoriginator_pal ( @originator_srv sysname, @originator_db sysname, @publication sysname ) as declare @retcode int /* ** Security Check, this is called by updatable subscriber in sync-tran proc, hence PAL access */ exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication if @@error <> 0 or @retcode <> 0 begin return (1) end exec @retcode = dbo.sp_replsetoriginator_internal @originator_srv, @originator_db if @@ERROR <> 0 or @retcode <> 0 begin return(1) end return 0 go exec sp_MS_marksystemobject sp_replsetoriginator_pal go grant execute on dbo.sp_replsetoriginator_pal to public go if exists (select * from sysobjects where type = 'X' and name = 'sp_replincrementlsn' ) exec dbo.sp_dropextendedproc 'sp_replincrementlsn' go if exists (select * from sysobjects where type = 'P' and name = 'sp_replincrementlsn' ) drop procedure sp_replincrementlsn if exists (select * from sysobjects where type = 'X' and name = 'sp_replincrementlsn_internal' ) exec dbo.sp_dropextendedproc 'sp_replincrementlsn_internal' go sp_addextendedproc 'sp_replincrementlsn_internal', 'replincrementlsn_internal extended procedure' go -- -- Name: -- sp_replincrementlsn -- -- Description: -- wrapper for sp_replincrementlsn_internal with DBO check -- -- Security: -- DBO only -- -- Returns: 0 : success -- 1 : failure -- -- Owner: -- qunguo -- -- raiserror('Creating procedure sp_replincrementlsn',0,1) go create proc sp_replincrementlsn ( @xact_seqno binary(10) OUTPUT ) as declare @retcode int /* ** Security Check, this proc is called by snapshot agent or sp_repladd(drop)column, against pub db as DBO */ exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 begin return(1) end exec @retcode = dbo.sp_replincrementlsn_internal @xact_seqno OUTPUT if @@ERROR <> 0 or @retcode <> 0 begin return(1) end return 0 go exec sp_MS_marksystemobject sp_replincrementlsn go grant execute on dbo.sp_replincrementlsn to public go if exists (select * from sysobjects where type = 'X' and name = 'sp_replpostsyncstatus' ) exec dbo.sp_dropextendedproc 'sp_replpostsyncstatus' if exists (select * from sysobjects where type = 'P' and name = 'sp_replpostsyncstatus' ) drop procedure sp_replpostsyncstatus if exists (select * from sysobjects where type = 'X' and name = 'sp_replpostsyncstatus_int' ) exec dbo.sp_dropextendedproc 'sp_replpostsyncstatus_int' go sp_addextendedproc 'sp_replpostsyncstatus_int', 'sp_replpostsyncstatus_int extended procedure' go -- -- Name: -- sp_replpostsyncstatus -- -- Description: -- wrapper for sp_replpostsyncstatus_int with DBO check -- -- Security: -- DBO only -- -- Returns: 0 : success -- 1 : failure -- -- Owner: -- qunguo -- -- raiserror('Creating procedure sp_replpostsyncstatus',0,1) go create proc sp_replpostsyncstatus ( @pubid int, @artid int, @syncstat int, @xact_seqno binary(10) OUTPUT ) as declare @retcode int /* ** Security Check, this proc is called by snapshot agent as DBO on publisher */ exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 begin return(1) end exec @retcode = dbo.sp_replpostsyncstatus_int @pubid, @artid, @syncstat, @xact_seqno OUTPUT if @@ERROR <> 0 or @retcode <> 0 begin return(1) end return 0 go exec sp_MS_marksystemobject sp_replpostsyncstatus go grant execute on dbo.sp_replpostsyncstatus to public go -------------------------------------------------------------------------------- --. System objects (repltran.sql) -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MScreate_pub_tables') drop procedure sp_MScreate_pub_tables print '' print 'Creating procedure sp_MScreate_pub_tables' go CREATE PROCEDURE sp_MScreate_pub_tables AS DECLARE @fError int SELECT @fError = 0 -- enable 'create tables as pseudo system tables -- sp_MS_upd_sysobj_category is obsolete, use sp_MS_marksystemobject instead -- exec dbo.sp_MS_upd_sysobj_category 1 /* ** Msg 226, Level 16, State 9 ** CREATE TABLE system-table command not allowed within multi-statement transaction. */ /* BEGIN TRAN sp_create_central_pub_tables */ /* Creating 'sysarticles' */ IF not exists (select * from sysobjects where name = 'sysarticles') BEGIN create table dbo.sysarticles ( artid int identity NOT NULL, columns varbinary(32) NULL, creation_script nvarchar(255) NULL, del_cmd nvarchar(255) NULL, description nvarchar(255) NULL, dest_table sysname NOT NULL, filter int NOT NULL, filter_clause ntext NULL, ins_cmd nvarchar(255) NULL, name sysname NOT NULL, objid int NOT NULL, pubid int NOT NULL, pre_creation_cmd tinyint NOT NULL, status tinyint NOT NULL, sync_objid int NOT NULL, type tinyint NOT NULL, upd_cmd nvarchar(255) NULL, schema_option binary(8) NULL, dest_owner sysname NULL -- Note: Please update sysextendedarticlesview whenever -- there is a schema change in sysarticles ) EXEC dbo.sp_MS_marksystemobject 'sysarticles' IF @@error<>0 BEGIN GOTO ERROR END create unique nonclustered index unc1sysarticles on sysarticles(artid, pubid) IF @@error<>0 BEGIN GOTO ERROR END END /* Creating 'sysschemaarticles' */ IF not exists (select * from sysobjects where name = 'sysschemaarticles') BEGIN create table dbo.sysschemaarticles ( artid int NOT NULL, creation_script nvarchar(255) NULL, description nvarchar(255) NULL, dest_object sysname NOT NULL, name sysname NOT NULL, objid int NOT NULL, pubid int NOT NULL, pre_creation_cmd tinyint NOT NULL, status int NOT NULL, type tinyint NOT NULL, schema_option binary(8) NULL, dest_owner sysname NULL ) IF @@error<>0 BEGIN GOTO ERROR END EXEC dbo.sp_MS_marksystemobject 'sysschemaarticles' IF @@error<>0 BEGIN GOTO ERROR END create unique nonclustered index unc1sysschemaarticles on sysschemaarticles(artid, pubid) IF @@error<>0 BEGIN GOTO ERROR END END /* Creating 'sysextendedarticlesview' */ IF not exists (select * from sysobjects where name = 'sysextendedarticlesview') BEGIN exec ('create view dbo.sysextendedarticlesview as select * from sysarticles union all select artid, NULL, creation_script, NULL, description, dest_object, NULL, NULL, NULL, name, objid, pubid, pre_creation_cmd, status, NULL, type, NULL, schema_option, dest_owner from sysschemaarticles go') IF @@error<>0 BEGIN GOTO ERROR END EXEC dbo.sp_MS_marksystemobject 'sysextendedarticlesview' IF @@error<>0 BEGIN GOTO ERROR END END /* Creating 'syspublications' */ IF NOT EXISTS (select * from sysobjects where name = 'syspublications') BEGIN CREATE TABLE dbo.syspublications ( description nvarchar(255) NULL, name sysname NOT NULL, pubid int identity NOT NULL, repl_freq tinyint NOT NULL, status tinyint NOT NULL, sync_method tinyint NOT NULL, snapshot_jobid binary(16) NULL, independent_agent bit NOT NULL, immediate_sync bit NOT NULL, enabled_for_internet bit NOT NULL, allow_push bit NOT NULL, allow_pull bit NOT NULL, allow_anonymous bit NOT NULL, immediate_sync_ready bit NOT NULL, -- SyncTran allow_sync_tran bit NOT NULL, autogen_sync_procs bit NOT NULL, retention int NULL, -- The following are post 7.0 allow_queued_tran bit default 0 not null, -- portable snapshot support snapshot_in_defaultfolder bit default 1 NOT NULL, alt_snapshot_folder nvarchar(255) NULL, -- snapshot pre/post- command pre_snapshot_script nvarchar(255) NULL, post_snapshot_script nvarchar(255) NULL, -- Snapshot compression compress_snapshot bit default 0 NOT NULL, -- Post 7.0 Ftp support ftp_address sysname NULL, ftp_port int default 21 NOT NULL, ftp_subdirectory nvarchar(255) NULL, ftp_login sysname NULL default N'anonymous', ftp_password nvarchar(524) NULL, allow_dts bit default 0 not null, allow_subscription_copy bit default 0 not null, centralized_conflicts bit NULL, -- 0 False, 1 True conflict_retention int NULL, -- 60 conflict_policy int NULL, -- 1 = PubWins, 2 = SubWins, 3 = Reinit queue_type int NULL, -- 1 = MSMQ, 2 = SQL ad_guidname sysname NULL, backward_comp_level int default 10 not NULL -- default is sphinx ) EXEC dbo.sp_MS_marksystemobject 'syspublications' IF @@ERROR <> 0 BEGIN GOTO ERROR END create unique clustered index uc1syspublications on syspublications (pubid) IF @@ERROR <> 0 BEGIN GOTO ERROR END create unique nonclustered index unc2syspublications on syspublications (name) IF @@ERROR <> 0 BEGIN GOTO ERROR END END /* Creating 'syssubscriptions' */ IF not exists (select * from sysobjects where name = 'syssubscriptions') BEGIN CREATE TABLE dbo.syssubscriptions ( artid int NOT NULL, srvid smallint NOT NULL, dest_db sysname NOT NULL, status tinyint NOT NULL, sync_type tinyint NOT NULL, login_name sysname NOT NULL, subscription_type int NOT NULL, distribution_jobid binary(16) NULL, timestamp NOT NULL, -- SyncTran update_mode tinyint NOT NULL, -- 0 (read only), 1 (Sync Tran), -- Queued Tran -- 2 (Queued Tran) , 3 (Failover), 4(sqlqueued), 5(sqlqueued failover) loopback_detection bit NOT NULL, queued_reinit bit DEFAULT 0 NOT NULL ) EXEC dbo.sp_MS_marksystemobject 'syssubscriptions' IF @@ERROR <> 0 BEGIN GOTO ERROR END create unique nonclustered index unc1syssubscriptions on syssubscriptions (artid, srvid, dest_db) IF @@ERROR <> 0 BEGIN GOTO ERROR END END -- SyncTran /* Creating 'sysarticleupdates' */ IF not exists (select * from sysobjects where name = 'sysarticleupdates') BEGIN CREATE TABLE dbo.sysarticleupdates ( artid int NOT NULL, pubid int NOT NULL, sync_ins_proc int NOT NULL, -- ID of sproc handling Insert Sync Transactions sync_upd_proc int NOT NULL, -- ID of sproc handling Update Sync Transactions sync_del_proc int NOT NULL, -- ID of sproc handling Delete Sync Transactions autogen bit NOT NULL, sync_upd_trig int NOT NULL, -- Note 7.0 upgrade issue conflict_tableid int NULL, -- ID of conflict table for this article ins_conflict_proc int NULL, -- ID of sproc to log conflicts identity_support bit default 0 not null -- Whether or not do auto identity range ) IF @@ERROR <> 0 BEGIN GOTO ERROR END -- mark the index as a system object exec dbo.sp_MS_marksystemobject 'sysarticleupdates' IF @@ERROR <> 0 BEGIN GOTO ERROR END create unique nonclustered index unc1sysarticleupdates on sysarticleupdates (artid, pubid) IF @@ERROR <> 0 BEGIN GOTO ERROR END END -- end SyncTran IF not exists (select * from sysobjects where name = 'MSpub_identity_range') BEGIN CREATE TABLE dbo.MSpub_identity_range ( objid int not null, range bigint not null, pub_range bigint not null, current_pub_range bigint not null, threshold int not null, last_seed bigint null -- It will be not when uninitialized. ) IF @@ERROR <> 0 BEGIN GOTO ERROR END -- mark the index as a system object exec dbo.sp_MS_marksystemobject 'MSpub_identity_range' IF @@ERROR <> 0 BEGIN GOTO ERROR END create unique nonclustered index unc1MSpub_identity_range on MSpub_identity_range (objid) IF @@ERROR <> 0 BEGIN GOTO ERROR END END IF not exists (select * from sysobjects where name = 'systranschemas' and uid = 1) BEGIN CREATE TABLE dbo.systranschemas ( tabid int not null, startlsn binary(10) not null, endlsn binary(10) not null ) IF @@ERROR <> 0 BEGIN GOTO ERROR END -- mark the index as a system object exec dbo.sp_MS_marksystemobject 'systranschemas' IF @@ERROR <> 0 BEGIN GOTO ERROR END create unique clustered index uncsystranschemas on systranschemas (startlsn) IF @@ERROR <> 0 BEGIN GOTO ERROR END END CLEANUP: -- disable 'create tables as pseudo system tables -- sp_MS_upd_sysobj_category is obsolete, use sp_MS_marksystemobject instead -- exec dbo.sp_MS_upd_sysobj_category 2 RETURN( @fError ) ERROR: select @fError = 1 GOTO CLEANUP GO EXEC dbo.sp_MS_marksystemobject sp_MScreate_pub_tables GO -------------------------------------------------------------------------------- --. sp_articlesynctranprocs -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_articlesynctranprocs') revoke exec on dbo.sp_articlesynctranprocs from public -------------------------------------------------------------------------------- --. sp_gettypestring -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_gettypestring') revoke exec on dbo.sp_gettypestring from public -------------------------------------------------------------------------------- --. sp_MSgettranconflictname -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgettranconflictname') revoke execute on dbo.sp_MSgettranconflictname from public -------------------------------------------------------------------------------- --. sp_MSmakeconflicttable -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeconflicttable') revoke execute on dbo.sp_MSmakeconflicttable from public -------------------------------------------------------------------------------- --. sp_MSmaketrancftproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmaketrancftproc') revoke execute on dbo.sp_MSmaketrancftproc from public -------------------------------------------------------------------------------- --. sp_MSmark_proc_norepl -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmark_proc_norepl') revoke execute on dbo.sp_MSmark_proc_norepl from public -------------------------------------------------------------------------------- --. sp_MSscript_beginproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_beginproc') revoke execute on dbo.sp_MSscript_beginproc from public -------------------------------------------------------------------------------- --. sp_MSscript_compensating_send -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_compensating_send') revoke execute on dbo.sp_MSscript_compensating_send from public -------------------------------------------------------------------------------- --. sp_MSscript_delete_pubwins -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_delete_pubwins') revoke execute on dbo.sp_MSscript_delete_pubwins from public -------------------------------------------------------------------------------- --. sp_MSscript_delete_statement -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_delete_statement') revoke execute on dbo.sp_MSscript_delete_statement from public -------------------------------------------------------------------------------- --. sp_MSscript_delete_subwins -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_delete_subwins') revoke execute on dbo.sp_MSscript_delete_subwins from public -------------------------------------------------------------------------------- --. sp_MSscript_ExecutionMode_stmt -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_ExecutionMode_stmt') revoke execute on dbo.sp_MSscript_ExecutionMode_stmt from public -------------------------------------------------------------------------------- --. sp_MSscript_insert_statement -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_insert_statement') revoke execute on dbo.sp_MSscript_insert_statement from public -------------------------------------------------------------------------------- --. sp_MSscript_security -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_security') revoke execute on dbo.sp_MSscript_security from public -------------------------------------------------------------------------------- --. sp_MSscript_update_statement -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_update_statement') revoke execute on dbo.sp_MSscript_update_statement from public -------------------------------------------------------------------------------- --. sp_scriptpkwhereclause -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptpkwhereclause') revoke exec on dbo.sp_scriptpkwhereclause from public -------------------------------------------------------------------------------- --. sp_scriptreconwhereclause -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptreconwhereclause') revoke exec on dbo.sp_scriptreconwhereclause from public -------------------------------------------------------------------------------- --. sp_scriptupdateparams -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptupdateparams') revoke exec on dbo.sp_scriptupdateparams from public go -------------------------------------------------------------------------------- --. sp_MSscript_ExecutionMode_stmt -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_ExecutionMode_stmt') drop procedure sp_MSscript_ExecutionMode_stmt go raiserror('Creating procedure sp_MSscript_ExecutionMode_stmt', 0,1) go create procedure sp_MSscript_ExecutionMode_stmt ( @publication sysname, @article sysname, @proctype int = 0) -- 0 insert, 1 delete, 2 update as begin declare @cmd nvarchar(4000) ,@artid int ,@pubid int ,@queued_pub bit select @pubid = pubid, @queued_pub = allow_queued_tran from syspublications where name = @publication select @artid = artid from sysarticles where name = @article and pubid = @pubid -- -- For queued execution check if we are in the phase of reinitialization -- select @cmd = N' ' + N'-- ' + N'-- Check if we are in the process of Reinitialization ' + N'-- if yes then return ' + N'--' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' exec @retcode = dbo.sp_MSgetarticlereinitvalue @orig_server, @orig_db, ' + cast(@artid as nvarchar(5)) + N', @reinit output if (@retcode != 0 or @@error != 0) return -1 ' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' if (@reinit = 1) -- Resync state begin if (@execution_mode = @immediate) return -2' if (@queued_pub = 1) begin select @cmd = @cmd + N' else return 4 -- Queued Resync state' end select @cmd = @cmd + N' end ' insert into #proctext(procedure_text) values( @cmd ) -- -- set loopback detection for immediate -- select @cmd = N' if (@execution_mode = @immediate) begin ' + N'-- ' + N'-- For immediate ' + N'-- enable loopback detection ' + N'-- exec @retcode = dbo.sp_replsetoriginator_pal @orig_server, @orig_db, ''' + master.dbo.fn_MSgensqescstr(@publication) collate database_default + N''' if (@retcode != 0 or @@error != 0) return -1 end' insert into #proctext(procedure_text) values( @cmd ) /********* no need to disable since we never enable if (@queued_pub = 1) begin -- -- disable loopback for queued -- select @cmd = N' else if (@execution_mode in (@QFirstPass, @QSubWins)) begin ' + N'-- ' + N'-- For queued ' + N'-- disable loopback detection ' + N'-- exec @retcode = dbo.sp_replsetoriginator N''anull'', N''anull'' if (@retcode != 0 or @@error != 0) return -1 end' insert into #proctext(procedure_text) values( @cmd ) end **********/ if (@queued_pub = 1) begin -- -- Queued reinitialization mode execution -- select @cmd = N' else if (@execution_mode = @QReinit) begin ' + N'-- ' + N'-- For Queued reinitialization ' + N'-- Set the Queue and subscription for reinit ' + N'--' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' exec @retcode = dbo.sp_reinitsubscription @publication = ''' + master.dbo.fn_MSgensqescstr(@publication) collate database_default + N''', @article = ''' + master.dbo.fn_MSgensqescstr(@article) collate database_default + N''', @subscriber = @orig_server, @destination_db = @orig_db if (@retcode != 0 or @@error != 0) return -1 else return 0 end' insert into #proctext(procedure_text) values( @cmd ) end -- -- all done -- return 0 end go EXEC dbo.sp_MS_marksystemobject sp_MSscript_ExecutionMode_stmt GO -------------------------------------------------------------------------------- --. sp_MSscript_pub_upd_trig -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_pub_upd_trig') drop procedure sp_MSscript_pub_upd_trig go raiserror('Creating procedure sp_MSscript_pub_upd_trig', 0,1) go create procedure sp_MSscript_pub_upd_trig ( @publication sysname, @article sysname, @procname sysname ) as begin declare @cmd nvarchar(4000) declare @qualname nvarchar(512) declare @objid int declare @columns binary(32) ,@retcode int set nocount on -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end -- Create temp table create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- Retrieve underlying table name and replicated columns select @objid = objid, @columns = columns from sysarticles a, syspublications p where a.name = @article and p.name = @publication and a.pubid = p.pubid exec sp_MSget_qualified_name @objid, @qualname OUTPUT -- Trigger should be invoked for repl processes as well. select @cmd = N'create trigger ' + QUOTENAME(@procname) + N' on ' + @qualname + N' ' select @cmd = @cmd + N'for update as ' exec dbo.sp_MSflush_command @cmd output, 1 insert into #proctext(procedure_text) values(N' ') -- declare common local variables insert into #proctext(procedure_text) values (N'declare @rc int ') insert into #proctext(procedure_text) values(N'select @rc = @@ROWCOUNT ') -- Optimization. Return immediately if no row changed -- This must be at the beginning of the trigger to @@rowcount be overwritten. insert into #proctext(procedure_text) values(N'if @rc = 0 return ') insert into #proctext(procedure_text) values(N'if update (msrepl_tran_version) return ') -- update the version column of all the updated rows all at once. select @cmd = N'update ' + @qualname + N' set msrepl_tran_version = newid() from ' + @qualname + ', inserted ' exec dbo.sp_MSflush_command @cmd output, 1 insert into #proctext(procedure_text) values(N' ') exec dbo.sp_MSscript_where_clause @objid, @columns, 'version pk', null, 4 insert into #proctext(procedure_text) values(N' ') -- send fragments to client select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_MSscript_pub_upd_trig go grant exec on dbo.sp_MSscript_pub_upd_trig to public go -------------------------------------------------------------------------------- --. sp_MSscript_sync_del_proc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_sync_del_proc') drop procedure sp_MSscript_sync_del_proc go raiserror('Creating procedure sp_MSscript_sync_del_proc', 0,1) go create procedure sp_MSscript_sync_del_proc ( @publication sysname, @article sysname, @procname sysname) as BEGIN declare @source_objid int declare @colname sysname declare @indid int declare @cmd nvarchar(4000) declare @columns binary(32) declare @outvars nvarchar(4000) declare @rc int declare @error_cmd tinyint declare @queued_pub bit set nocount on -- -- security check -- exec @rc = dbo.sp_MSreplcheck_publish if @@error <> 0 or @rc <> 0 begin return (1) end -- -- Create temp table -- create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) select @queued_pub = allow_queued_tran from syspublications where name = @publication -- -- proc definition -- exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output if @rc = 0 return -- -- construct parameter list -- exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null -- -- add other parameters and start body of proc -- exec dbo.sp_MSscript_procbodystart @queued_pub -- -- script out security check -- exec dbo.sp_MSscript_security @publication -- -- script the execution mode checks -- exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 1 -- -- script out subscription validation -- exec dbo.sp_MSscript_validate_subscription @publication, @article -- -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp) -- *** Do we need to check this here - -- *** we should be checking this when creating subscription -- exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns if @rc = 1 select @error_cmd = 1 else begin exec @indid = dbo.sp_MStable_has_unique_index @source_objid if (@outvars != null and @indid = 0) -- no insert/update allowed if timestamp/identity col and no unique index select @error_cmd = 1 else select @error_cmd = 0 end if (@error_cmd = 0) begin -- Continue generation -- -- script delete statemnt -- exec dbo.sp_MSscript_delete_statement @publication, @article, @source_objid, @columns, @queued_pub -- -- script queued specific stuff -- if (@queued_pub = 1) begin -- -- script Conflict resolution block for Subscriber Wins case -- exec dbo.sp_MSscript_delete_subwins @publication, @article, @source_objid, @columns -- -- script Conflict resolution block for Publisher Wins case -- exec dbo.sp_MSscript_delete_pubwins @publication, @article, @source_objid, @columns end -- -- script closing -- exec dbo.sp_MSscript_endproc @source_objid, 'del', @columns, @outvars, @queued_pub end else begin -- -- Generate error command and finish -- insert into #proctext(procedure_text) values( N' exec sp_MSreplraiserror 20516 END ') end -- -- send fragments to client -- select procedure_text from #proctext order by c1 asc END go EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_del_proc GO grant exec on dbo.sp_MSscript_sync_del_proc to public go -------------------------------------------------------------------------------- --. sp_MSscript_sync_ins_proc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_sync_ins_proc') drop procedure sp_MSscript_sync_ins_proc go raiserror('Creating procedure sp_MSscript_sync_ins_proc', 0,1) go create procedure sp_MSscript_sync_ins_proc ( @publication sysname, @article sysname, @procname sysname) as BEGIN declare @source_objid int ,@colname sysname ,@indid int ,@cmd nvarchar(4000) ,@columns binary(32) ,@outvars nvarchar(4000) ,@rc int ,@error_cmd tinyint ,@identity_insert bit ,@queued_pub bit set nocount on -- -- security check -- exec @rc = dbo.sp_MSreplcheck_publish if @@error <> 0 or @rc <> 0 begin return (1) end -- -- Create temp table -- create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) select @queued_pub = allow_queued_tran from syspublications where name = @publication -- -- proc definition -- exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output if @rc = 0 return -- -- construct parameter list -- exec dbo.sp_MSscript_params @source_objid, @columns, null, 1, @outvars output -- -- add other parameters and start body of proc -- exec dbo.sp_MSscript_procbodystart @queued_pub -- -- script out security check -- exec dbo.sp_MSscript_security @publication -- -- script the execution mode checks -- exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 0 -- -- script out subscription validation -- exec dbo.sp_MSscript_validate_subscription @publication, @article -- -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp) -- *** Do we need to check this here - -- *** we should be checking this when creating subscription -- exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns if @rc = 1 select @error_cmd = 1 else begin exec @indid = dbo.sp_MStable_has_unique_index @source_objid if (@outvars != null and @indid = 0) -- no insert/update allowed if timestamp/identity col and no unique index select @error_cmd = 1 else select @error_cmd = 0 end if (@error_cmd = 0) begin -- Continue generation -- Check to see if identity insert must be turned on -- i.e. Does the table has identity that are included in the partition? exec sp_MSis_identity_insert @publication, @article, @identity_insert output -- -- script insert statemnt -- exec dbo.sp_MSscript_insert_statement @source_objid, @columns, @identity_insert, @queued_pub -- -- script queued specific stuff -- if (@queued_pub = 1) begin -- -- script Conflict resolution block for Subscriber Wins case -- exec dbo.sp_MSscript_insert_subwins @publication, @article, @source_objid, @columns, @identity_insert -- -- script Conflict resolution block for Publisher Wins case -- exec dbo.sp_MSscript_insert_pubwins @publication, @article, @source_objid, @columns end -- -- script closing -- exec dbo.sp_MSscript_endproc @source_objid, 'ins', @columns, @outvars, @queued_pub end else begin -- -- Generate error command and finish -- insert into #proctext(procedure_text) values( N' exec sp_MSreplraiserror 20516 END ') end -- -- send fragments to client -- select procedure_text from #proctext order by c1 asc END go EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_ins_proc GO grant exec on dbo.sp_MSscript_sync_ins_proc to public go -------------------------------------------------------------------------------- --. sp_MSscript_sync_upd_proc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_sync_upd_proc') drop procedure sp_MSscript_sync_upd_proc go raiserror('Creating procedure sp_MSscript_sync_upd_proc', 0,1) go create procedure sp_MSscript_sync_upd_proc ( @publication sysname, @article sysname, @procname sysname) as BEGIN declare @source_objid int ,@colname sysname ,@indid int ,@cmd nvarchar(4000) ,@columns binary(32) ,@outvars nvarchar(4000) ,@rc int ,@error_cmd tinyint ,@identity_insert bit ,@queued_pub bit set nocount on -- -- security check -- exec @rc = dbo.sp_MSreplcheck_publish if @@error <> 0 or @rc <> 0 begin return (1) end -- -- Create temp table -- create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) select @queued_pub = allow_queued_tran from syspublications where name = @publication -- -- proc definition -- exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output if @rc = 0 return -- -- construct parameter list -- Script bitmap parameter -- exec dbo.sp_MSscript_params @source_objid, @columns, null, 1, @outvars output insert into #proctext(procedure_text) values( N',') exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null insert into #proctext(procedure_text) values( N' ,@bitmap varbinary(4000)') -- -- add other parameters and start body of proc -- exec dbo.sp_MSscript_procbodystart @queued_pub -- -- script out security check -- exec dbo.sp_MSscript_security @publication -- -- script the execution mode checks -- exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 2 -- -- script out subscription validation -- exec dbo.sp_MSscript_validate_subscription @publication, @article -- -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp) -- *** Do we need to check this here - -- *** we should be checking this when creating subscription -- exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns if @rc = 1 select @error_cmd = 1 else begin exec @indid = dbo.sp_MStable_has_unique_index @source_objid if (@outvars != null and @indid = 0) -- no insert/update allowed if timestamp/identity col and no unique index select @error_cmd = 1 else select @error_cmd = 0 end if (@error_cmd = 0) begin -- Continue generation -- -- script update statemnt -- exec dbo.sp_MSscript_update_statement @publication, @article, @source_objid, @columns, @queued_pub -- -- script queued specific stuff -- if (@queued_pub = 1) begin -- Check to see if identity insert must be turned on -- i.e. Does the table has identity that are included in the partition? exec sp_MSis_identity_insert @publication, @article, @identity_insert output -- -- -- script Conflict resolution block for Subscriber Wins case -- exec dbo.sp_MSscript_update_subwins @publication, @article, @source_objid, @columns, @identity_insert -- -- script Conflict resolution block for Publisher Wins case -- exec dbo.sp_MSscript_update_pubwins @publication, @article, @source_objid, @columns end -- -- script closing -- exec dbo.sp_MSscript_endproc @source_objid, 'upd', @columns, @outvars, @queued_pub end else begin -- -- Generate error command and finish -- insert into #proctext(procedure_text) values( N' exec sp_MSreplraiserror 20516 END ') end -- -- send fragments to client -- select procedure_text from #proctext order by c1 asc END go EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_upd_proc GO grant exec on dbo.sp_MSscript_sync_upd_proc to public go -------------------------------------------------------------------------------- --. sp_script_reconciliation_insproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_script_reconciliation_insproc') drop procedure sp_script_reconciliation_insproc go raiserror('Creating procedure sp_script_reconciliation_insproc', 0,1) go create procedure sp_script_reconciliation_insproc ( @artid int) as BEGIN declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @artcolumns binary(32) declare @pkcolumns binary(32) declare @ins_cmd nvarchar(255) declare @dest_proc sysname declare @this_col int declare @art_col int declare @isset int declare @typestring nvarchar(255) declare @spacer nvarchar(1) , @identity_insert bit -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @artcolumns = columns, @ins_cmd = ins_cmd from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -- Check to see if identity insert must be turned on -- i.e. Does the table has identity that are included in the partition? exec sp_MSis_identity_insert null, null, @identity_insert output, @artid -- -------- get dest proc name if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 ) select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2' -------- construct parameter list select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- save off cmd fragment insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) ------- construct proc body ---- if already exists, apply as update insert into #proctext(procedure_text) values( N'if exists ( select * from ' + @dest_owner + QUOTENAME(@dest_tabname) ) exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns insert into #proctext(procedure_text) values( N')' ) insert into #proctext(procedure_text) values (N'begin') if( @artcolumns != @pkcolumns ) begin -- construct update select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' -- create SET clause select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset = 0 begin if not (@identity_insert = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns end -- all article columns are included in the PK, & PK already exists, do nothing else begin insert into #proctext(procedure_text ) values( N'return' ) end insert into #proctext(procedure_text) values (N'end') insert into #proctext(procedure_text) values (N'else') insert into #proctext(procedure_text) values (N'begin') ---- normal insert -- set identity_insert on if @identity_insert = 1 begin select @cmd = N' set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on' insert into #proctext(procedure_text) values( @cmd ) end -- prepare the column list select @cmd = N'insert into ' + @dest_owner + QUOTENAME(@dest_tabname) + N' (' select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- now the data parameter list select @cmd = @cmd + N' ) values (' select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- finish up proc body select @cmd = @cmd + N' )' -- save off cmd fragement insert into #proctext(procedure_text) values( @cmd ) -- set identity_insert off if @identity_insert = 1 begin select @cmd = N' set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off' insert into #proctext(procedure_text) values( @cmd ) end insert into #proctext(procedure_text) values (N'end') -- send fragments to client select procedure_text from #proctext order by c1 asc END go EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_insproc GO grant exec on dbo.sp_script_reconciliation_insproc to public go -------------------------------------------------------------------------------- --. sp_script_reconciliation_delproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_script_reconciliation_delproc') drop procedure sp_script_reconciliation_delproc go raiserror('Creating procedure sp_script_reconciliation_delproc', 0,1) go create procedure sp_script_reconciliation_delproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @pkcolumns binary(32) declare @del_cmd nvarchar(255) declare @dest_proc sysname declare @this_col int declare @art_col int declare @isset int declare @typestring nvarchar(255) declare @spacer nvarchar(10) -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @del_cmd = del_cmd from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -------- get dest proc name if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 ) select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2' -------- construct parameter list select @art_col = 1 select @spacer = N' ' exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid ) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- save off insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) ------- construct proc body insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns -- flush to client select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_delproc GO grant exec on dbo.sp_script_reconciliation_delproc to public go -------------------------------------------------------------------------------- --. sp_script_reconciliation_xdelproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_script_reconciliation_xdelproc') drop procedure sp_script_reconciliation_xdelproc go raiserror('Creating procedure sp_script_reconciliation_xdelproc', 0,1) go create procedure sp_script_reconciliation_xdelproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @columns binary(32) declare @pkcolumns binary(32) declare @del_cmd nvarchar(255) declare @dest_proc sysname declare @this_col int declare @art_col int declare @isset int declare @typestring nvarchar(255) declare @spacer nvarchar(10) -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @del_cmd = del_cmd, @columns = columns from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -------- get dest proc name if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 ) select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2' -------- construct parameter list select @art_col = 1 select @spacer = N' ' exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- save off insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) ------- construct proc body insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns -- flush to client select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_xdelproc GO grant exec on dbo.sp_script_reconciliation_xdelproc to public go -------------------------------------------------------------------------------- --. sp_scriptinsproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptinsproc') drop procedure sp_scriptinsproc go raiserror('Creating procedure sp_scriptinsproc', 0,1) go create procedure sp_scriptinsproc ( @artid int) as BEGIN declare @cmd nvarchar(4000) ,@dest_owner nvarchar(255) ,@dest_tabname sysname ,@src_objid int ,@columns binary(32) ,@ins_cmd nvarchar(255) ,@dest_proc sysname ,@this_col int ,@art_col int ,@isset int ,@pubid int ,@identity_insert bit ,@rc int ,@colname sysname ,@ccoltype sysname ,@typestring nvarchar(255) ,@spacer nvarchar(1) ,@queued_check bit ,@column_string nvarchar(4000) ,@var_string nvarchar(4000) set nocount on -- -- security check -- exec @rc = dbo.sp_MSreplcheck_publish if @@error <> 0 or @rc <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments and insert column list create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) create table #collisttab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @columns = columns, @ins_cmd = ins_cmd, @pubid = pubid from sysarticles where artid = @artid -- Check to see if identity insert must be turned on -- i.e. Does the table has identity that are included in the partition? exec sp_MSis_identity_insert null, null, @identity_insert output, @artid -- if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -- Check if this is a queued publication select @queued_check = ISNULL(allow_queued_tran, 0) from syspublications where pubid = @pubid -------- get dest proc name if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) -------- construct parameter list select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- save off cmd fragment insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' AS BEGIN ' insert into #proctext(procedure_text) values( @cmd ) ------- construct proc body -- Generate strings for col names and variables select @art_col = 0 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @rc = dbo.sp_MSget_colinfo @src_objid, @this_col, @columns, 1, @colname output, @ccoltype output if @rc = 0 and EXISTS (select name from syscolumns where id=@src_objid and colid=@this_col and iscomputed<>1) begin select @art_col = @art_col + 1 if (@art_col = 1) begin select @column_string = QUOTENAME(@colname) select @var_string = N'@c' + cast(@art_col as nvarchar(4)) end else begin select @column_string = @column_string + N', ' + QUOTENAME(@colname) select @var_string = @var_string + N', @c' + cast(@art_col as nvarchar(4)) end -- transfer column list string to table if too large if (len(@column_string) > 3000) begin insert into #collisttab(procedure_text) values( @column_string ) select @column_string = ' ' end end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- insert the remaining strings for column list and where clause insert into #collisttab(procedure_text) values( @column_string ) -- -- If we are a part of queued publication then -- insert only if PK or other unique key(s) do not exist -- if (@queued_check = 1) begin select @cmd = N' if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' ' insert into #proctext(procedure_text) values( @cmd ) exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid ,@columns = @columns ,@prefix = '@c' ,@mode = 1 if (@@error != 0 or @rc != 0) return 1 select @cmd = N') BEGIN' insert into #proctext(procedure_text) values( @cmd ) end -- set identity_insert on if @identity_insert = 1 begin select @cmd = N' set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on' insert into #proctext(procedure_text) values( @cmd ) end -- -- prepare the insert statement now -- select @cmd = N' insert into ' + @dest_owner + QUOTENAME(@dest_tabname) + N'( ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #collisttab order by c1 asc select @cmd = N' )' insert into #proctext(procedure_text) values( @cmd ) if @art_col > 0 begin select @cmd = N' values ( ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( @var_string ) select @cmd = N' ) ' insert into #proctext(procedure_text) values( @cmd ) end -- set identity_insert off if @identity_insert = 1 begin select @cmd = N' set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off' insert into #proctext(procedure_text) values( @cmd ) end -- -- If we are a part of queued publication then -- add the block delimiter -- drop table #collisttab if (@queued_check = 1) begin select @cmd = N' END END' end else select @cmd = N' END' insert into #proctext(procedure_text) values( @cmd ) -- send fragements to client select procedure_text from #proctext order by c1 asc END go EXEC dbo.sp_MS_marksystemobject sp_scriptinsproc GO grant exec on dbo.sp_scriptinsproc to public go -------------------------------------------------------------------------------- --. sp_scriptdelproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptdelproc') drop procedure sp_scriptdelproc go raiserror('Creating procedure sp_scriptdelproc', 0,1) go create procedure sp_scriptdelproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @pkcolumns binary(32) declare @del_cmd nvarchar(255) declare @dest_proc sysname declare @this_col int declare @art_col int declare @isset int, @pubid int declare @typestring nvarchar(255) declare @spacer nvarchar(10) -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @del_cmd = del_cmd, @pubid = pubid from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -------- get dest proc name if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) -------- construct parameter list select @art_col = 1 select @spacer = N' ' exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid ) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- save off insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) ------- construct proc body insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns if exists (select * from syspublications where pubid = @pubid and allow_queued_tran = 0) exec dbo.sp_MSscript_missing_row_check -- flush to client select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_scriptdelproc GO grant exec on dbo.sp_scriptdelproc to public go -------------------------------------------------------------------------------- --. sp_scriptxdelproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptxdelproc') drop procedure sp_scriptxdelproc go raiserror('Creating procedure sp_scriptxdelproc', 0,1) go create procedure sp_scriptxdelproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @columns binary(32) declare @pkcolumns binary(32) declare @del_cmd nvarchar(255) declare @dest_proc sysname declare @this_col int declare @art_col int declare @isset int declare @pubid int declare @typestring nvarchar(255) declare @spacer nvarchar(10) declare @queued_check bit ,@qwhere_string nvarchar(4000) -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- get sysarticles information select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @del_cmd = del_cmd, @columns = columns from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -- Check if this is a queued publication select @queued_check = ISNULL(allow_queued_tran, 0) from syspublications where pubid = @pubid -------- get dest proc name if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) -------- construct parameter list select @art_col = 1 select @spacer = N' ' exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring -- -- Queued processing:if this is the row version column : need to add to where clause -- if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version')) select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col ) select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- save off insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) ------- construct proc body insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns if (@queued_check = 1) insert into #proctext(procedure_text) values( @qwhere_string ) else exec dbo.sp_MSscript_missing_row_check -- flush to client select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_scriptxdelproc GO grant exec on dbo.sp_scriptxdelproc to public go -------------------------------------------------------------------------------- --. sp_scriptupdproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptupdproc') drop procedure sp_scriptupdproc go raiserror('Creating procedure sp_scriptupdproc', 0,1) go create procedure sp_scriptupdproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @artcolumns binary(32) declare @pkcolumns binary(32) declare @upd_cmd nvarchar(255) declare @dest_proc sysname declare @this_col int declare @art_col int declare @pkart_col int declare @isset int declare @pkcomputed int declare @typestring nvarchar(255) declare @spacer nvarchar(10) declare @pubid int, @allow_queued_tran bit, @need_end bit -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end select @need_end = 0 if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -------- get sysarticles information select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -------- get dest proc name if( 1 != charindex( N'CALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid declare @keep_identity bit if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1 select @keep_identity = 1 else select @keep_identity = 0 select @dest_proc = substring( @upd_cmd, 6, len( @upd_cmd ) - 4 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ') -------- construct parameter list exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns insert into #proctext(procedure_text) values ( N'as' ) -------- now create the update statement -- construct test to see if pk has changed -- only do this if the article has columns not included in the pk exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns declare @pk_is_identity bit select @pk_is_identity = 0 if @artcolumns != @pkcolumns and @pkcomputed = 0 begin select @cmd = N'if' select @art_col = 1 select @pkart_col = 1 select @spacer = ' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col select @pk_is_identity = 1 WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @pk_is_identity = 0 select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col ) + N' = @pkc' + convert( nvarchar, @pkart_col ) select @spacer = N' and ' select @pkart_col = @pkart_col + 1 if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid if @pk_is_identity = 0 begin insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'begin' ) -- construct update if pk hasn't changed select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' -- create SET clause select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset = 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns if @allow_queued_tran <> 1 exec dbo.sp_MSscript_missing_row_check insert into #proctext(procedure_text) values( N'end' ) insert into #proctext(procedure_text) values( N'else' ) insert into #proctext(procedure_text) values( N'begin' ) select @need_end = 1 end end -- end if artcols != pkcols -- construct update if pk has changed select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' -- create SET clause select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns if @allow_queued_tran <> 1 exec dbo.sp_MSscript_missing_row_check if @need_end = 1 insert into #proctext(procedure_text) values( N'end' ) -- flush to client select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_scriptupdproc GO grant exec on dbo.sp_scriptupdproc to public go -------------------------------------------------------------------------------- --. sp_scriptmappedupdproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptmappedupdproc') drop procedure sp_scriptmappedupdproc go raiserror('Creating procedure sp_scriptmappedupdproc', 0,1) go create procedure sp_scriptmappedupdproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @artcolumns binary(32) declare @pkcolumns binary(32) declare @upd_cmd nvarchar(255) declare @dest_proc sysname declare @art_cols int declare @this_col int declare @art_col int declare @pkart_col int declare @isset int declare @bytestr nvarchar(10) declare @bitstr nvarchar(10) declare @typestring nvarchar(255) declare @spacer nvarchar(10) declare @update_created bit declare @pkcomputed int declare @pubid int, @allow_queued_tran bit -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end select @update_created = 0 if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd, @pubid = pubid from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -------- get dest proc name if( 1 != charindex( N'MCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid declare @keep_identity bit if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1 select @keep_identity = 1 else select @keep_identity = 0 select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' ) -------- construct parameter list exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns ----- add changed data bitmap select @art_col = 1 DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) begin select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- Note that bitmap size is based on number of article columns -- (computed by loop above) not source table columns select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) -- construct IF statement to examine colbitmap and determine if a -- primary key column has been updated. -- do this only if the article contains columns not included in the pk -- and at least one of the columns in the PK is real ( i.e. not computed ) -- note that if all the article columns are PK columns, we will -- construct the 'update all columns including PK columns' statement -- w/o a preceeding IF, and we will NOT construct the 'only update non-pk columns' -- part of the procedure -- also note that this is pretty much worthless since 7.0 and above are -- guaranteed to NEVER generate an UPDATE if a PK columns is updated... oh well. declare @pk_is_identity bit select @pk_is_identity = 0 exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns if @artcolumns != @pkcolumns and @pkcomputed = 0 begin select @art_col = 1 select @spacer = N' ' select @cmd = N'if' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col select @pk_is_identity = 1 WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @pk_is_identity = 0 select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 ) select @bitstr = convert( nvarchar, power(2, (@art_col-1) % 8 ) ) select @cmd = @cmd + @spacer + N'substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr + N' = ' + @bitstr select @spacer = N' or ' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid if @pk_is_identity = 0 insert into #proctext(procedure_text) values( @cmd ) end -- if artcolumns != pkcolumns -- construct update statement including PK columns insert into #proctext(procedure_text) values( N'begin' ) insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' ) -- create SET clause consisting of CASE statements select @art_col = 1 select @spacer = N'' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 ) select @bitstr = convert( nvarchar, power(2, (@art_col-1) % 8 ) ) insert into #proctext(procedure_text) values ( @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' ) select @spacer = ',' end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- create where clause exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns if @allow_queued_tran <> 1 exec dbo.sp_MSscript_missing_row_check -- construct UPDATE that does not set PK cols -- only do this if the article contains columns that are not included -- in the pk if @artcolumns != @pkcolumns and @pkcomputed = 0 and @pk_is_identity = 0 begin -- create SET clause consisting of CASE statements select @art_col = 1 select @spacer = N'' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset = 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin if (@update_created = 0) begin insert into #proctext(procedure_text) values( N'end' ) insert into #proctext(procedure_text) values( N'else' ) insert into #proctext(procedure_text) values( N'begin' ) insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' ) select @update_created = 1 end select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 ) select @bitstr = convert( nvarchar, power(2, (@art_col-1) % 8 ) ) insert into #proctext(procedure_text) values ( @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' ) select @spacer = ',' end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid if @update_created = 1 begin exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns if @allow_queued_tran <> 1 exec dbo.sp_MSscript_missing_row_check end end insert into #proctext(procedure_text) values( N'end' ) select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_scriptmappedupdproc GO grant exec on dbo.sp_scriptmappedupdproc to public go -------------------------------------------------------------------------------- --. sp_scriptdynamicupdproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptdynamicupdproc') drop procedure sp_scriptdynamicupdproc go raiserror('Creating procedure sp_scriptdynamicupdproc', 0,1) go create procedure sp_scriptdynamicupdproc ( @artid int ) as begin declare @retcode int declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @artcolumns binary(32) declare @pkcolumns binary(32) declare @upd_cmd nvarchar(255) declare @dest_proc sysname declare @art_cols int declare @this_col int declare @art_col int declare @pk_col int declare @pkart_col int declare @isset int declare @ispk int declare @isidentity bit declare @iscomputed bit declare @bytestr nvarchar(10) declare @bitstr nvarchar(10) declare @typestring nvarchar(255) declare @spacer_param nvarchar(10) declare @update_created bit declare @pkcomputed int declare @pubid int, @allow_queued_tran bit set nocount on -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end select @update_created = 0 if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) create table #proctext_params ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) create table #proctext_paramdef ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) create table #proctext_pkparams ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd, @pubid = pubid from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -------- get dest proc name if( 1 != charindex( N'MCALL', upper(@upd_cmd) ) ) or @upd_cmd is null begin raiserror (14156, 16, 1 ) return 1 end select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid declare @keep_identity bit if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1 select @keep_identity = 1 else select @keep_identity = 0 select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' ) -------- construct parameter list exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns ----- add changed data bitmap select @art_col = 1 select @pk_col = 1 DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) begin select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- Note that bitmap size is based on number of article columns -- (computed by loop above) not source table columns select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'as' ) -- Find out if pk is identity declare @pk_is_identity bit select @pk_is_identity = 0 exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns if @artcolumns != @pkcolumns and @pkcomputed = 0 begin select @art_col = 1 DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col select @pk_is_identity = 1 WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @pk_is_identity = 0 end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid end -- construct UPDATE that does not set PK cols -- only do this if the article contains columns that are not included -- in the pk -- Note: we assume pk columns never change. pk changes will be replicated -- as delete insert. if @artcolumns != @pkcolumns and @pkcomputed = 0 and @pk_is_identity = 0 begin -- create SET clause consisting of CASE statements select @art_col = 1 select @spacer_param = N'' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 begin exec @ispk = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid) select @iscomputed = 0 else select @iscomputed = 1 if (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) select @isidentity = 1 else select @isidentity = 0 -- If not pk, not computed and not identity if @ispk = 0 and @iscomputed = 0 and @isidentity = 0 begin if (@update_created = 0) begin insert into #proctext(procedure_text) values( N'declare @stmt nvarchar(4000), @spacer nvarchar(1)') insert into #proctext(procedure_text) values( N'select @spacer =N''''') insert into #proctext(procedure_text) values( N'select @stmt = N''update ' + replace(@dest_owner + QUOTENAME(@dest_tabname), N'''', N'''''' ) + N' set ''') select @update_created = 1 end select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 ) select @bitstr = convert( nvarchar, power(2, (@art_col-1) % 8 ) ) insert into #proctext(procedure_text) values ( N'if substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr + N' = ' + @bitstr) insert into #proctext(procedure_text) values (N'begin') -- Append statement insert into #proctext(procedure_text) values ( N'select @stmt = @stmt + @spacer + ' + N'N''' + replace(QUOTENAME(col_name( @src_objid, @this_col)), N'''', N'''''') + N''' + ' + N'N''=@'+ convert( nvarchar, @art_col ) + N'''') -- Set @spacer is the proc insert into #proctext(procedure_text) values ( N'select @spacer = N'',''') insert into #proctext(procedure_text) values (N'end') end -- If pk or (not computed and not identity) add the param if @ispk <> 0 or (@iscomputed = 0 and @isidentity = 0) begin -- Add to param list if (@ispk <> 0) begin -- Use primary key value insert into #proctext_params(procedure_text) values( @spacer_param + N'@pkc' + convert( nvarchar, @pk_col )) -- Increment primary key counter select @pk_col = @pk_col + 1; end else -- Use column value insert into #proctext_params(procedure_text) values( @spacer_param + N'@c' + convert( nvarchar, @art_col )) -- Get type str exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT -- Append typedef insert into #proctext_paramdef(procedure_text) values ( @spacer_param + N'@' + convert( nvarchar, @art_col ) + N' ' + @typestring ) select @spacer_param = ',' end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid if @update_created = 1 begin -- Append statement of the start of where clause insert into #proctext(procedure_text) values ( N' select @stmt = @stmt + N'' ') -- Escape ' in the where clause declare @low_mark int, @high_mark int select @low_mark = max(c1) from #proctext -- Pass in @artcolumns so that the where clause will use the ordinal in the -- article bit map rather then one in pk bitmap. This is consistent with -- the type def string. -- UNDONE: change comments in sp_scriptpkwhereclause -- Use prefix '@' to be consistent with type def string exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, '@', @artcolumns select @high_mark = max(c1) from #proctext update #proctext set procedure_text = replace ( procedure_text, N'''', N'''''') where c1 > @low_mark and c1 <= @high_mark -- Close the where clause insert into #proctext(procedure_text) values ( N'''') -- Add call to sql_executesql and the param list insert into #proctext(procedure_text) values( N'exec sp_executesql @stmt, N'' ') -- Add param def insert into #proctext(procedure_text) select procedure_text from #proctext_paramdef order by c1 asc -- Close the param def insert into #proctext(procedure_text) values ( N''',') -- Add param list insert into #proctext(procedure_text) select procedure_text from #proctext_params order by c1 asc if @allow_queued_tran <> 1 exec dbo.sp_MSscript_missing_row_check end end select procedure_text from #proctext order by c1 asc end go EXEC dbo.sp_MS_marksystemobject sp_scriptdynamicupdproc GO grant exec on dbo.sp_scriptdynamicupdproc to public go -------------------------------------------------------------------------------- --. sp_scriptxupdproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_scriptxupdproc') drop procedure sp_scriptxupdproc go raiserror('Creating procedure sp_scriptxupdproc', 0,1) go create procedure sp_scriptxupdproc @artid int as BEGIN declare @cmd nvarchar(4000), @dest_owner nvarchar(255), @dest_tabname sysname, @src_objid int, @artcolumns binary(32), @pkcolumns binary(32), @upd_cmd nvarchar(255), @dest_proc sysname, @this_col int, @art_col int, --@pkart_col int, @isset int, @rc int, @fhasnonpkuniquekeys int, @pkcomputed int, @typestring nvarchar(255), @spacer nvarchar(10), @pubid int, @param_count int ,@queued_check bit, @exists_else bit ,@qwhere_string nvarchar(4000) set nocount on -- -- security check -- exec @rc = dbo.sp_MSreplcheck_publish if @@error <> 0 or @rc <> 0 begin return (1) end if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 ) begin raiserror (14155, 16, 1 ) return 1 end select @exists_else = 0 ,@fhasnonpkuniquekeys = 0 -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -------- get sysarticles information select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -- Check if this is a queued publication select @queued_check = ISNULL(allow_queued_tran, 0) from syspublications where pubid = @pubid -------- get dest proc name if( 1 != charindex( N'XCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null begin raiserror (14156, 16, 1 ) return 1 end declare @keep_identity bit if exists (select * from syspublications where pubid = @pubid and allow_queued_tran = 1) and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1 select @keep_identity = 1 else select @keep_identity = 0 select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 ) select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''') drop proc ' + QUOTENAME(@dest_proc) insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'go' ) insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ') -------- construct parameter list exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output -- Send null as @pkcolumns. We don't need pk parameters. exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, NULL, @param_count output insert into #proctext(procedure_text) values ( N'as' ) -- -- If we are a part of queued publication -- if (@queued_check = 1) begin -- -- Check if we have non PK unique keys -- exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @src_objid if (@fhasnonpkuniquekeys = 1) begin -- -- There are non PK unique keys -- update only if updated values of non PK unique key(s) do not exist -- select @cmd = N' if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' ' insert into #proctext(procedure_text) values( @cmd ) exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid ,@columns = @artcolumns ,@prefix = '@c' ,@mode = 2 ,@paramcount = @param_count if (@@error != 0 or @rc != 0) return 1 select @cmd = N') begin' insert into #proctext(procedure_text) values( @cmd ) end end -------- now create the update statement -- construct test to see if pk has changed -- only do this if the article has columns not included in the pk exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns declare @pk_is_identity bit select @pk_is_identity = 0 if @artcolumns != @pkcolumns and @pkcomputed = 0 begin select @cmd = N'if' select @art_col = 1 --select @pkart_col = 1 select @spacer = ' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col select @pk_is_identity = 1 WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @pk_is_identity = 0 select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col + @param_count/2) + N' = @c' + convert( nvarchar, @art_col ) select @spacer = N' and ' --select @pkart_col = @pkart_col + 1 if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid if @pk_is_identity = 0 begin insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N'begin' ) -- construct update if pk hasn't changed -- We know that there would be a least one column for the update below, even if -- the columns outside the pk are identity or timestamp. Since identity and timestamp -- will be mapped off unless it is queued tran. In that case, we have 'msrepl_tran_version' select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' -- create SET clause select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset = 0 begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col + @param_count/2) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end -- -- Queued processing:if this is the row version column : need to add to where clause -- if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version')) select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col ) end end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns if (@queued_check = 1) insert into #proctext(procedure_text) values( @qwhere_string ) else exec dbo.sp_MSscript_missing_row_check insert into #proctext(procedure_text) values( N'end' ) insert into #proctext(procedure_text) values( N'else' ) insert into #proctext(procedure_text) values( N'begin' ) select @exists_else = 1 end end -- end if artcols != pkcols -- -- If we are a part of queued publication then -- update only if updated value of PK does not exist -- if (@queued_check = 1 and @pk_is_identity = 0) begin select @cmd = N' if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' ' insert into #proctext(procedure_text) values( @cmd ) exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid ,@columns = @artcolumns ,@prefix = '@c' ,@mode = 3 ,@paramcount = @param_count if (@@error != 0 or @rc != 0) return 1 select @cmd = N') begin' insert into #proctext(procedure_text) values( @cmd ) end -- construct update if pk has changed select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' -- create SET clause select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1) begin if not (@keep_identity = 1 and columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1) begin select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col + @param_count/2 ) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end -- -- Queued processing:if this is the row version column : need to add to where clause -- if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version')) select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col ) end select @art_col = @art_col + 1 end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns if (@queued_check = 1) begin insert into #proctext(procedure_text) values( @qwhere_string ) if (@pk_is_identity = 0) begin select @cmd = N' end' insert into #proctext(procedure_text) values( @cmd ) end end else exec dbo.sp_MSscript_missing_row_check if @exists_else = 1 insert into #proctext(procedure_text) values( N'end' ) -- -- End the if exists block for Queued publications -- if (@queued_check = 1) and (@fhasnonpkuniquekeys = 1) begin select @cmd = N' end' insert into #proctext(procedure_text) values( @cmd ) end -- flush to client select procedure_text from #proctext order by c1 asc END go EXEC dbo.sp_MS_marksystemobject sp_scriptxupdproc GO grant exec on dbo.sp_scriptxupdproc to public go -------------------------------------------------------------------------------- --. sp_MSgetarticlereinitvalue -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetarticlereinitvalue') drop procedure sp_MSgetarticlereinitvalue go raiserror('Creating procedure sp_MSgetarticlereinitvalue', 0,1) go create procedure sp_MSgetarticlereinitvalue ( @subscriber sysname, @subscriberdb sysname, @artid int, @reinit int output ) as begin set NOCOUNT ON declare @orig_srvid int ,@retcode int ,@publication sysname -- -- PAL security check -- Get publication name using artid -- select @publication = p.name from syspublications p join sysarticles a on p.pubid = a.pubid where a.artid = @artid if (@publication is null) begin return 1 end exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication if @@error <> 0 or @retcode <> 0 begin return (1) end -- -- get the value of reinit flag -- select @orig_srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default select @reinit = queued_reinit from syssubscriptions where artid = @artid and srvid = @orig_srvid and dest_db = @subscriberdb -- All done return 0 end go exec dbo.sp_MS_marksystemobject sp_MSgetarticlereinitvalue go grant execute on dbo.sp_MSgetarticlereinitvalue to public go -------------------------------------------------------------------------------- --. sp_MScomputearticlescreationorder -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MScomputearticlescreationorder') drop procedure sp_MScomputearticlescreationorder go print '' print 'Creating procedure sp_MScomputearticlescreationorder' go CREATE PROCEDURE sp_MScomputearticlescreationorder @publication sysname AS SET NOCOUNT ON DECLARE @pubid int DECLARE @max_level int DECLARE @current_level int DECLARE @update_level int DECLARE @limit int DECLARE @result int DECLARE @retcode int SELECT @retcode = 0 EXEC @retcode = sp_MSreplcheck_publish IF @@ERROR <> 0 OR @retcode <> 0 return (1) SELECT @pubid = NULL -- Get the pubid from syspublications SELECT @pubid = pubid FROM syspublications WHERE name = @publication IF @@ERROR <> 0 RETURN (1) IF @pubid IS NULL BEGIN RAISERROR(20026, 16, -1, @publication) RETURN (1) END EXEC @result = sp_getapplock @Resource = @publication, @LockMode = N'Shared', @LockOwner = N'Session', @LockTimeout = 0 IF @result < 0 BEGIN RAISERROR(21385, 16, -1, @publication) RETURN (1) END -- Find out the total number of articles in this publication and -- compute the maximum tree height based on the number of articles in -- the publication. Here, the tree height is counted from the -- leaf-nodes towards the root(s) SELECT @max_level = COUNT(*) + 10, @limit =2 * COUNT(*) + 11 FROM sysextendedarticlesview WHERE pubid = @pubid IF @@ERROR <> 0 BEGIN RETURN (1) END -- The following temp table contains the minimal amount of -- article information that we want to keep around and the current -- computed tree level of the article CREATE TABLE #article_level_info ( article sysname collate database_default not null, source_objid INT NOT NULL, tree_level INT NOT NULL, ref_level INT NOT NULL, major_type TINYINT NOT NULL -- 1-view&func, 0-other ) CREATE CLUSTERED INDEX ucarticle_level_info ON #article_level_info(source_objid) IF @@ERROR <> 0 BEGIN GOTO Failure END -- Populate the article level info table. All articles will be -- assigned 0 as their initial tree level. Having -- a tree level of 0 means that the algorithm hasn't discovered -- any objects that the article depends on within the publication. INSERT INTO #article_level_info SELECT name, objid, 0, 0, CASE type WHEN 0x40 THEN 1 WHEN 0x80 THEN 1 ELSE 0 END FROM sysextendedarticlesview WHERE pubid = @pubid -- To jump-start the algorithm, update the tree_level of -- all articles with no dependency to @max_level. UPDATE #article_level_info SET tree_level = @max_level WHERE NOT EXISTS (SELECT * FROM sysdepends WHERE source_objid = id and id <> depid) IF @@ERROR <> 0 GOTO Failure -- For each increasing tree level starting from @max_level, update the -- the tree_level of articles depending on objects at the current -- level to current level + 1 SELECT @current_level = @max_level WHILE 1 = 1 BEGIN SELECT @update_level = @current_level + 1 UPDATE #article_level_info SET tree_level = @update_level FROM #article_level_info INNER JOIN sysdepends d ON #article_level_info.source_objid = d.id INNER JOIN #article_level_info ali1 ON (d.depid = ali1.source_objid AND ali1.tree_level = @current_level AND d.id <> d.depid) -- Terminate the algorithm if we cannot find any articles -- depending on articles at the current level IF @@ROWCOUNT = 0 GOTO PHASE1 IF @@ERROR <> 0 GOTO Failure SELECT @current_level = @current_level + 1 -- Although there should not be any circular -- dependencies among the articles, the following -- check is performed to guarantee that -- the algorithm will terminate even if there -- is circular dependency among the articles -- Note that with at least one node per level, -- the current level can never exceed the total -- number of articles (nodes) unless there is -- circular dependency among the articles. -- @limit is defined to be # of articles + 1 -- although @limit = # of articles - 1 will be -- sufficient. This is to make absolutely sure that -- the algorithm will never terminate too early IF @current_level > @limit GOTO PHASE1 END PHASE1: -- There may be interdependencies among articles -- that haven't been included in the previous calculations so -- we compute the proper order among these articles here. SELECT @limit = @max_level - 9 SELECT @current_level = 0 WHILE 1 = 1 BEGIN SELECT @update_level = @current_level + 1 UPDATE #article_level_info SET tree_level = @update_level FROM #article_level_info INNER JOIN sysdepends d ON (#article_level_info.source_objid = d.id AND #article_level_info.tree_level < @max_level) INNER JOIN #article_level_info ali1 ON (d.depid = ali1.source_objid AND ali1.tree_level = @current_level AND d.id <> d.depid) IF @@ROWCOUNT = 0 GOTO PHASE2 IF @@ERROR <> 0 GOTO Failure SELECT @current_level = @current_level + 1 IF @current_level > @limit GOTO PHASE2 END PHASE2: -- Since transactional doesn't keep the nickname around in -- sysmergearticles as merge does, we need to compute FK/PK ordering on -- the fly. SELECT @current_level = 0 SELECT @limit = @max_level - 9 WHILE 1 = 1 BEGIN SELECT @update_level = @current_level + 1 UPDATE #article_level_info SET ref_level = @update_level FROM #article_level_info INNER JOIN sysreferences r ON (#article_level_info.source_objid = r.fkeyid and r.rkeyid <> r.fkeyid) INNER JOIN #article_level_info ali1 ON (r.rkeyid = ali1.source_objid AND ali1.ref_level = @current_level) IF @@ROWCOUNT = 0 GOTO PHASE3 IF @@ERROR <> 0 GOTO Failure SELECT @current_level = @current_level + 1 IF @current_level > @limit GOTO PHASE3 END PHASE3: -- Select the articles out of #article_level_info -- in ascending order of tree_level. This will give -- the proper order in which articles can be created -- without violating the internal dependencies among -- themselves. Note that this algorithm still allows -- unresolved external references outside the publication. -- All this algorithm can guarantee is that all articles will -- be created successfully using the resulting order if -- there is no dependent object outside the publication. -- We need to order the articles in reverse ref_level -- to account for FK/PK constraints when dropping/deleting rows/truncating -- tables on the Subscriber. SELECT article FROM #article_level_info ORDER BY major_type ASC, tree_level ASC, ref_level DESC DROP TABLE #article_level_info RETURN (0) Failure: DROP TABLE #article_level_info RETURN (1) GO exec dbo.sp_MS_marksystemobject sp_MScomputearticlescreationorder go grant execute on sp_MScomputearticlescreationorder to public go -------------------------------------------------------------------------------- --. sp_MSscriptmvastablenci -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscriptmvastablenci') drop procedure sp_MSscriptmvastablenci go print '' print 'Creating procedure sp_MSscriptmvastablenci' go create procedure sp_MSscriptmvastablenci @artid int as declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @constraint_name sysname declare @spacer nvarchar(1) declare @srcobj nvarchar(1000) declare @colname sysname declare @indkey int declare @indid int declare @status int declare @unique nvarchar(10) declare @cmd_sep nvarchar(10) -------- security check, db_owner declare @retcode int exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default select @cmd_sep = N'' DECLARE hCIdx CURSOR LOCAL FAST_FORWARD FOR select name, indid, status from sysindexes where id = @src_objid and indid > 1 order by indid asc OPEN hCIdx FETCH hCIdx INTO @constraint_name, @indid, @status WHILE (@@fetch_status <> -1) begin if @status & 2 = 2 begin select @unique = N' unique ' end else begin select @unique = N' ' end insert into #proctext(procedure_text) values( @cmd_sep ) select @cmd_sep = N'GO' select @cmd = N'create' + @unique + N'nonclustered index ' + QUOTENAME(@constraint_name) + N' on ' +@dest_owner + QUOTENAME(@dest_tabname) + N'(' insert into #proctext(procedure_text) values( @cmd ) select @spacer = N' ' select @cmd = N'' select @indkey = 1 while (@indkey <= 16) begin select @colname = index_col(@srcobj, @indid, @indkey) if (@colname is null) begin select @indkey = 16 end else begin select @cmd = @cmd + @spacer + QUOTENAME(@colname) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end select @indkey = @indkey + 1 end insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N')' ) FETCH hCIdx INTO @constraint_name, @indid, @status end CLOSE hCIdx DEALLOCATE hCIdx select procedure_text from #proctext order by c1 asc go EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastablenci GO grant exec on dbo.sp_MSscriptmvastablenci to public go -------------------------------------------------------------------------------- --. sp_MSscriptmvastablepkc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscriptmvastablepkc') drop procedure sp_MSscriptmvastablepkc go print '' print 'Creating procedure sp_MSscriptmvastablepkc' go create procedure sp_MSscriptmvastablepkc @artid int as declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @constraint_name sysname declare @spacer nvarchar(1) declare @srcobj nvarchar(1000) declare @colname sysname declare @indkey int declare @indid int -------- security check, db_owner declare @retcode int exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default select @constraint_name = name, @indid = indid from sysindexes where id = @src_objid and status & 16 <> 0 select @cmd = N'alter table ' + @dest_owner + QUOTENAME(@dest_tabname) collate database_default + N' add constraint ' + QUOTENAME(@constraint_name) collate database_default + N' primary key clustered (' insert into #proctext(procedure_text) values( @cmd ) select @spacer = N' ' select @cmd = N'' select @indkey = 1 while (@indkey <= 16) begin select @colname = index_col(@srcobj, @indid, @indkey) if (@colname is null) begin select @indkey = 16 end else begin select @cmd = @cmd + @spacer + QUOTENAME(@colname) collate database_default select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end select @indkey = @indkey + 1 end insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N')' ) select procedure_text from #proctext order by c1 asc go EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastablepkc GO grant exec on dbo.sp_MSscriptmvastablepkc to public go -------------------------------------------------------------------------------- --. sp_MSscriptmvastableidx -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscriptmvastableidx') drop procedure sp_MSscriptmvastableidx go print '' print 'Creating procedure sp_MSscriptmvastableidx' go create procedure sp_MSscriptmvastableidx @artid int as declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @constraint_name sysname declare @spacer nvarchar(1) declare @srcobj nvarchar(1000) declare @colname sysname declare @indkey int declare @indid int -------- security check, db_owner declare @retcode int exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default select @constraint_name = name, @indid = indid from sysindexes where id = @src_objid and status & 16 <> 0 select @cmd = N'create unique clustered index ' + QUOTENAME(@constraint_name) + N' on ' +@dest_owner + QUOTENAME(@dest_tabname) + N'(' insert into #proctext(procedure_text) values( @cmd ) select @spacer = N' ' select @cmd = N'' select @indkey = 1 while (@indkey <= 16) begin select @colname = index_col(@srcobj, @indid, @indkey) if (@colname is null) begin select @indkey = 16 end else begin select @cmd = @cmd + @spacer + QUOTENAME(@colname) select @spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end select @indkey = @indkey + 1 end insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) values( N')' ) select procedure_text from #proctext order by c1 asc go EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastableidx GO grant exec on dbo.sp_MSscriptmvastableidx to public go -------------------------------------------------------------------------------- --. sp_MSscriptmvastable -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscriptmvastable') drop procedure sp_MSscriptmvastable go print '' print 'Creating procedure sp_MSscriptmvastable' go create procedure sp_MSscriptmvastable @artid int as declare @cmd nvarchar(4000) declare @dest_owner nvarchar(255) declare @dest_tabname sysname declare @src_objid int declare @artcolumns binary(32) declare @schema_option binary(8) declare @art_col int declare @this_col int declare @isset int declare @use_base_type tinyint declare @spacer nvarchar(1) declare @nullability nvarchar(10) declare @typestring nvarchar(255) declare @col_name sysname -------- security check, db_owner declare @retcode int exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) -------- create temp table for command fragments create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default ) -------- get sysarticles information select @dest_owner = dest_owner, @dest_tabname = dest_table, @src_objid = objid, @artcolumns = columns, @use_base_type = substring(schema_option,8,1) & 32 from sysarticles where artid = @artid if @dest_owner is not null begin select @dest_owner = QUOTENAME( @dest_owner ) + N'.' end else begin select @dest_owner = N'' end -- script out CREATE TABLE statement -- begin create table select @cmd = N'create table ' + @dest_owner + QUOTENAME(@dest_tabname) + N'(' insert into #proctext(procedure_text) values( @cmd ) -- columns select @art_col = 1 select @spacer = N' ' DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @src_objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns select @col_name = name, @nullability = case isnullable when 0 then N'NOT NULL' else N'NULL' end from syscolumns where id=@src_objid and @this_col=colid if @isset != 0 and @col_name is not null begin if @use_base_type <> 0 begin exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT end else begin exec dbo.sp_MSgettypestringudt @src_objid, @this_col, @typestring OUTPUT end select @cmd = @spacer + QUOTENAME(@col_name) + N' ' + @typestring + N' ' + @nullability insert into #proctext(procedure_text) values( @cmd ) select @art_col = @art_col + 1 select @spacer = N',' end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- end create table insert into #proctext(procedure_text) values( N')' ) select procedure_text from #proctext order by c1 asc go EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastable GO grant exec on dbo.sp_MSscriptmvastable to public go -------------------------------------------------------------------------------- --. sp_verify_publication -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_verify_publication') revoke execute on sp_verify_publication to public go -------------------------------------------------------------------------------- --. sp_MSscript_insert_subwins -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_insert_subwins') drop procedure sp_MSscript_insert_subwins go raiserror('Creating procedure sp_MSscript_insert_subwins', 0,1) go create procedure sp_MSscript_insert_subwins ( @publication sysname, @article sysname, @objid int, @columns binary(32), @identity_insert bit) AS BEGIN declare @cmd nvarchar(4000) ,@qualname nvarchar(512) ,@column_string nvarchar(4000) ,@var_string nvarchar(4000) ,@colname sysname ,@ccoltype sysname ,@this_col int ,@rc int ,@num_col int exec sp_MSget_qualified_name @objid, @qualname OUTPUT select @cmd = N' if (@error in (0, 547, 2601, 2627) and @execution_mode = @QSubWins) begin ' + N'-- ' + N'-- Subscriber Wins resolution ' + N'-- if (@rowcount = 1 and @error = 0) begin' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- ' + N'-- No conflict for this command ' + N'-- do nothing ' + N'-- will remove this code block later ' + N'-- for optimization ' + N'-- select @retcode = 0 end' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' else if (@rowcount = 0 and @error in (547, 2601, 2627)) begin ' + N'-- ' + N'-- Conflict for this command ' + N'-- Row already exists ' + N'-- delete and insert row with Queue values ' + N'-- ' insert into #proctext(procedure_text) values( @cmd ) -- -- script delete -- select @cmd = N' delete ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0 -- -- script the insert assignment -- select @num_col = 0 create table #worktab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) create table #worktab2 ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status != -1) begin exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1) begin if rtrim(@ccoltype) not like N'timestamp' begin select @num_col = @num_col + 1 select @column_string = QUOTENAME(@colname) select @var_string = N'@c' + cast(@this_col as nvarchar(4)) if (@num_col > 1) begin select @column_string = N', ' + @column_string select @var_string = N', ' +@var_string end insert into #worktab(procedure_text) values( @column_string ) insert into #worktab2(procedure_text) values( @var_string ) end end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid if (@num_col > 0) begin if (@identity_insert = 1) begin -- Only to call set if identity is not marked for 'not for repl' -- This is to avoid security failure of 'SET' for PAL users if not exists (select * from syscolumns where id = @objid and ColumnProperty(id, name, 'IsIdNotForRepl') = 1) begin select @cmd = N' set identity_insert ' + @qualname + N' on ' insert into #proctext(procedure_text) values( @cmd ) end end select @cmd = N' insert into ' + @qualname + N'( ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #worktab order by c1 asc select @cmd = N' ) values ( ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #worktab2 order by c1 asc select @cmd = N' )' insert into #proctext(procedure_text) values( @cmd ) if (@identity_insert = 1) begin -- Only to call set if identity is not marked for 'not for repl' -- This is to avoid security failure of 'SET' for PAL users if not exists (select * from syscolumns where id = @objid and ColumnProperty(id, name, 'IsIdNotForRepl') = 1) begin select @cmd = N' set identity_insert ' + @qualname + N' off ' insert into #proctext(procedure_text) values( @cmd ) end end end select @cmd = N' if (@@error != 0 or @retcode != 0) return -1 end else return -1 end' insert into #proctext(procedure_text) values( @cmd ) -- -- all done -- drop table #worktab drop table #worktab2 return 0 END go exec dbo.sp_MS_marksystemobject sp_MSscript_insert_subwins go -------------------------------------------------------------------------------- --. sp_MSscript_insert_pubwins -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_insert_pubwins') drop procedure sp_MSscript_insert_pubwins go raiserror('Creating procedure sp_MSscript_insert_pubwins', 0,1) go create procedure sp_MSscript_insert_pubwins ( @publication sysname, @article sysname, @objid int, @columns binary(32) ) AS BEGIN declare @cmd nvarchar(4000) ,@artid int ,@pubid int ,@dest_table sysname ,@dest_owner nvarchar(260) ,@colname sysname ,@ccoltype sysname ,@this_col int ,@rc int ,@num_col int ,@qualname nvarchar(512) ,@cast_str nvarchar(1000) ,@decl_str nvarchar(2000) ,@assign_str nvarchar(4000) ,@typestring nvarchar(100) ,@exec_str nvarchar(1000) -- -- initialize the vars we will use -- select @pubid = pubid from syspublications where name = @publication select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner from sysarticles where name = @article and pubid = @pubid select @dest_owner = case when (@dest_owner IS NULL) then N'' else quotename(@dest_owner) + N'.' end exec sp_MSget_qualified_name @objid, @qualname OUTPUT -- -- start script generation -- select @cmd = N' else if (@error in (0, 547, 2601, 2627) and @execution_mode = @QPubWins) begin ' + N'-- ' + N'-- Publisher Wins resolution ' + N'-- Find where we have to generate compensating action ' + N'-- if (@rowcount = 1 and @error = 0) begin' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- ' + N'-- No conflict for this command ' + N'-- Row does not exist ' + N'-- Generate delete compensating action ' + N'-- select @cftcase = 23' insert into #proctext(procedure_text) values( @cmd ) -- -- Continue with scripting -- select @cmd = N' end else if (@rowcount = 0 and @error in (547, 2601, 2627)) begin ' + N'-- ' + N'-- conflict for this command ' + N'-- Row already exists ' + N'-- generate update compensating action ' + N'-- DELETE compensating command + INSERT compensating command ' + N'-- select @cftcase = 21' insert into #proctext(procedure_text) values( @cmd ) -- -- continue with scripting -- select @cmd = N' end else return -1 ' + N'-- ' + N'-- generate compensating command according to the cases ' + N'--' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' if (@cftcase in (21,23)) begin ' + N'-- ' + N'-- delete compensating command ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- Generate the delete compensating code -- select @cmd = N' select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + ' insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins' exec sp_MSscript_compensating_send @pubid, @artid, 0, 1 select @cmd = N' end if (@cftcase = 21) begin ' + N'-- ' + N'-- insert compensating command ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- generate the compensating insert command -- exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 0 -- -- continue with scripting -- select @cmd = N' end end' insert into #proctext(procedure_text) values( @cmd ) -- -- all done -- return 0 END go exec dbo.sp_MS_marksystemobject sp_MSscript_insert_pubwins go -------------------------------------------------------------------------------- --. sp_MSscript_update_subwins -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_update_subwins') drop procedure sp_MSscript_update_subwins go raiserror('Creating procedure sp_MSscript_update_subwins', 0,1) go create procedure sp_MSscript_update_subwins ( @publication sysname, @article sysname, @objid int, @columns binary(32), @identity_insert bit) AS BEGIN declare @cmd nvarchar(4000) ,@artid int ,@pubid int ,@qualname nvarchar(512) ,@column_string nvarchar(4000) ,@colname sysname ,@ccoltype sysname ,@this_col int ,@rc int ,@num_col int ,@art_col int ,@bitstr nvarchar(20) ,@bytestr nvarchar(20) ,@isset int ,@timestamp_subscribed bit -- -- initialize the vars we will use -- select @pubid = pubid from syspublications where name = @publication select @artid = artid from sysarticles where name = @article and pubid = @pubid exec sp_MSget_qualified_name @objid, @qualname OUTPUT -- -- special flag for timestamp column subscription -- if exists (select * from sysarticles where pubid = @pubid and name = @article and status & 32 <> 0) select @timestamp_subscribed = 1 else select @timestamp_subscribed = 0 -- -- start scripting -- select @cmd = N' if (@error in (0, 547, 2601, 2627) and @execution_mode = @QSubWins) begin ' + N'-- ' + N'-- Subscriber Wins resolution ' + N'-- select @retcode = 0 if (@rowcount = 0) begin -- -- Conflict for this command -- Check if PK update was being done --' insert into #proctext(procedure_text) values( @cmd ) -- -- script the PK update check -- select @cmd = N' exec @retcode = dbo.sp_MSispkupdateinconflict ' + cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' if (@retcode = -1) return -1 if (@retcode = 0) begin ' + N'-- ' + N'-- PK update is not being done ' + N'-- ' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using OLD_PK -- select @cmd = N' if exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0 insert into #proctext(procedure_text) values( N' )') -- -- continue scripting -- select @cmd = N' begin ' + N'-- ' + N'-- row with OLD_PK exists ' + N'-- update row with OLD_PK with queue values ' + N'-- select @cftcase = 11 end' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' else begin ' + N'-- ' + N'-- row with OLD_PK does not exists ' + N'-- insert row with queue values using OLD_PK ' + N'-- select @cftcase = 13 end end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' else begin ' + N'-- ' + N'-- PK update is being done ' + N'-- drop rows with OLD_PK, NEW_PK and insert row with queue values ' + N'-- select @cftcase = 0' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using OLD_PK -- select @cmd = N' if exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0 insert into #proctext(procedure_text) values( N' )') -- -- continue scripting -- select @cmd = N' begin ' + N'-- ' + N'-- row with OLD_PK exists ' + N'-- insert row with queue values using NEW_PK + ' + N'-- delete row with OLD_PK ' + N'-- select @cftcase = 14 end' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using NEW_PK -- select @cmd = N' if exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0 insert into #proctext(procedure_text) values( N' )') -- -- continue scripting -- select @cmd = N' begin ' + N'-- ' + N'-- row with NEW_PK exists ' + N'-- case 15: rows with NEW_PK and OLD_PK exist ' + N'-- update row with NEW_PK with queue values + ' + N'-- delete row with OLD_PK' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- case 16: row with NEW_PK exists ' + N'-- update row with NEW_PK with queue values ' + N'-- select @cftcase = case when (@cftcase = 14) then 15 else 16 end end' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' if (@cftcase = 0) begin ' + N'-- ' + N'-- no existing rows with OLD_PK or NEW_PK ' + N'-- insert with queue values ' + N'-- select @cftcase = 12 end end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' ' + N'-- ' + N'-- based on retcode do the resolution ' + N'-- if (@cftcase in (12, 13, 14)) begin ' + N'-- ' + N'-- insert ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- prepare the insert statement -- if (@identity_insert = 1) begin -- Only to call set if identity is not marked for 'not for repl' -- This is to avoid security failure of 'SET' for PAL users if not exists (select * from syscolumns where id = @objid and ColumnProperty(id, name, 'IsIdNotForRepl') = 1) begin select @cmd = N' set identity_insert ' + @qualname + N' on ' insert into #proctext(procedure_text) values( @cmd ) end end select @cmd = N' insert into ' + @qualname + N'(' insert into #proctext(procedure_text) values( @cmd ) select @num_col = 0 ,@art_col = 0 ,@cmd = NULL create table #collisttab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) create table #worktab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from dbo.syscolumns where id = @objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status != -1) begin -- Get the ordinal of the article partition or not. exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns if @isset = 0 begin if ((@timestamp_subscribed = 1) and exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189)) select @art_col = @art_col + 1 end else select @art_col = @art_col + 1 exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output if @rc = 0 and EXISTS (select name from dbo.syscolumns where id=@objid and colid=@this_col and iscomputed<>1) begin if rtrim(@ccoltype) != N'timestamp' begin select @num_col = @num_col + 1 ,@bytestr = cast((1 + (@art_col-1) / 8 ) as nvarchar) ,@bitstr = cast( power(2, (@art_col-1) % 8 ) as nvarchar) select @column_string = N'case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + N' then @c' + cast(@this_col as nvarchar(4)) + N' else @c' + cast(@this_col as nvarchar(4)) + N'_old end ' if (@num_col = 1) begin select @cmd = quotename(@colname) select @column_string = N' ' + @column_string end else begin select @cmd = @cmd + N',' + quotename(@colname) select @column_string = N' , ' + @column_string end -- transfer the column list string to table if large if (len(@cmd) > 3000) begin insert into #collisttab(procedure_text) values( @cmd ) select @cmd = N' ' end insert into #worktab(procedure_text) values( @column_string ) end end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- transfer the remaining column list string to table insert into #collisttab(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #collisttab order by c1 asc select @cmd = N') select ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #worktab order by c1 asc if (@identity_insert = 1) begin -- Only to call set if identity is not marked for 'not for repl' -- This is to avoid security failure of 'SET' for PAL users if not exists (select * from syscolumns where id = @objid and ColumnProperty(id, name, 'IsIdNotForRepl') = 1) begin select @cmd = N' set identity_insert ' + @qualname + N' off ' insert into #proctext(procedure_text) values( @cmd ) end end -- -- continue with scripting -- select @cmd = N' end if (@cftcase = 11) begin ' + N'-- ' + N'-- update using OLD_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- prepare the column list for update statement -- select @num_col = 0 ,@art_col = 0 create table #worktab2 ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid from syscolumns where id = @objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col WHILE (@@fetch_status <> -1) begin -- Get the ordinal of the article partition or not. exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns if @isset = 0 begin if ((@timestamp_subscribed = 1) and exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189)) select @art_col = @art_col + 1 end else select @art_col = @art_col + 1 exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1) begin if (rtrim(@ccoltype) != N'timestamp') and ColumnProperty(@objid, @colname, 'IsIdentity') != 1 begin select @num_col = @num_col + 1 ,@bytestr = cast((1 + (@art_col-1) / 8 ) as nvarchar) ,@bitstr = cast( power(2, (@art_col-1) % 8 ) as nvarchar) select @column_string = quotename(@colname) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + N' then @c' + cast(@this_col as nvarchar(4)) + N' else @c' + cast(@this_col as nvarchar(4)) + N'_old end ' if (@num_col = 1) begin select @column_string = N' ' + @column_string end else begin select @column_string = N' , ' + @column_string end insert into #worktab2(procedure_text) values( @column_string ) end end FETCH hCColid INTO @this_col end CLOSE hCColid DEALLOCATE hCColid -- -- script the update with OLD_PK statement -- select @cmd = N' update ' + @qualname + N' set ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #worktab2 order by c1 asc exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0 -- -- continue with scripting -- select @cmd = N' end if (@cftcase in (15, 16)) begin ' + N'-- ' + N'-- update using NEW_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- script the update with NEW_PK statement -- select @cmd = N' update ' + @qualname + N' set ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from #worktab2 order by c1 asc exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0 -- -- continue with scripting -- select @cmd = N' end if (@cftcase in (14, 15)) begin ' + N'-- ' + N'-- Do not delete if subscriber has already ' + N'-- updated this row as part of this transaction ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using OLD_PK and msprepl_tran_version -- select @cmd = N' if not exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'subwins_check', 'msrepl_tran_version', 0 insert into #proctext(procedure_text) values( N' )') select @cmd = N' begin ' + N'-- ' + N'-- delete row with OLD_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- script delete with OLD_PK -- select @cmd = N' delete ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0 -- -- continue with rest of scripting -- select @cmd = N' end end if (@@error != 0) return -1 select @retcode = 0 end end' insert into #proctext(procedure_text) values( @cmd ) -- -- all done -- drop table #collisttab drop table #worktab drop table #worktab2 return 0 END go exec dbo.sp_MS_marksystemobject sp_MSscript_update_subwins go -------------------------------------------------------------------------------- --. sp_MSscript_update_pubwins -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_update_pubwins') drop procedure sp_MSscript_update_pubwins go raiserror('Creating procedure sp_MSscript_update_pubwins', 0,1) go create procedure sp_MSscript_update_pubwins ( @publication sysname, @article sysname, @objid int, @columns binary(32) ) AS BEGIN declare @cmd nvarchar(4000) ,@artid int ,@pubid int ,@dest_table sysname ,@dest_owner nvarchar(260) ,@colname sysname ,@ccoltype sysname ,@this_col int ,@rc int ,@num_col int ,@qualname nvarchar(512) ,@cast_str nvarchar(1000) ,@decl_str nvarchar(2000) ,@assign_str nvarchar(4000) ,@typestring nvarchar(100) ,@exec_str nvarchar(1000) ,@fhasnonpkuniquekeys int -- -- initialize the vars we will use -- select @pubid = pubid from syspublications where name = @publication select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner from sysarticles where name = @article and pubid = @pubid select @dest_owner = case when (@dest_owner IS NULL) then N'' else quotename(@dest_owner) + N'.' end exec sp_MSget_qualified_name @objid, @qualname OUTPUT -- -- start scripting -- select @cmd = N' else if (@error in (0, 547, 2601, 2627) and @execution_mode = @QPubWins) begin ' insert into #proctext(procedure_text) values( @cmd ) -- -- special declare for case when we have non PK unique keys -- exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid if (@fhasnonpkuniquekeys = 1) begin declare @spacer nvarchar(5) ,@art_col int ,@isset int ,@pkcolumns varbinary(32) select @cmd = N' declare ' ,@spacer = N'' ,@art_col = 1 exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output declare #hccolid cursor local fast_forward for select colid from syscolumns where id = @objid order by colid asc open #hccolid fetch #hccolid into @this_col while (@@fetch_status != -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 and exists ( select name from syscolumns where id=@objid and colid=@this_col and iscomputed !=1 ) begin exec dbo.sp_gettypestring @objid, @this_col, @typestring output select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring select @art_col = @art_col + 1 ,@spacer = N',' if len( @cmd ) > 3000 begin insert into #proctext(procedure_text) values( @cmd ) select @cmd = N'' end end fetch #hccolid into @this_col end close #hccolid deallocate #hccolid if len(@cmd) > 0 insert into #proctext(procedure_text) values( @cmd ) end -- -- continue scripting -- select @cmd = N' if (@rowcount = 1) begin ' + N'-- ' + N'-- no conflict for this command ' + N'-- Check if PK update was being done ' + N'-- ' insert into #proctext(procedure_text) values( @cmd ) -- -- script the PK update check -- select @cmd = N' exec @retcode = dbo.sp_MSispkupdateinconflict ' + cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' if (@retcode = -1) return -1 if (@retcode = 0) begin ' + N'-- ' + N'-- PK update is not being done ' + N'-- generate delete + insert compensating action with OLD_PK ' + N'-- select @cftcase = 0 end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' else begin ' + N'-- ' + N'-- PK update is being done ' + N'-- generate delete + insert compensating action with OLD_PK ' + N'-- generate delete compensating action with NEW_PK ' + N'-- select @cftcase = 1 end end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' else begin ' + N'-- ' + N'-- Conflict for this command ' + N'-- Check if PK update was being done ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- script the PK update check -- select @cmd = N' exec @retcode = dbo.sp_MSispkupdateinconflict ' + cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' if (@retcode = -1) return -1 if (@retcode = 0) begin ' + N'-- ' + N'-- PK update is not being done ' + N'-- Now find the type of conflict ' + N'-- ' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using OLD_PK -- select @cmd = N' if exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0 insert into #proctext(procedure_text) values( N' )') -- -- continue scripting -- select @cmd = N' begin ' + N'-- ' + N'-- row exists ' + N'-- generate delete + insert compensating action with OLD_PK ' + N'-- select @cftcase = 11' insert into #proctext(procedure_text) values( @cmd ) -- -- special scripting for table with unique keys -- if (@fhasnonpkuniquekeys = 1) begin select @cmd = N' if (@error in (2601, 2627)) begin ' + N'-- ' + N'-- Unique key violation ' + N'-- case 15 : row with OLD_PK exist and row with NEW_UNK exists ' + N'-- generate delete compensating action with OLD_PK' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- insert compensating action with OLD_PK ' + N'-- insert compensating action with rows that qualify the NEW_UNKEYS ' + N'-- select @cftcase = 15 end' insert into #proctext(procedure_text) values( @cmd ) end select @cmd = N' end' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' else begin ' + N'-- ' + N'-- row does not exist ' + N'-- generate delete compensating action with OLD_PK ' + N'-- select @cftcase = 13' insert into #proctext(procedure_text) values( @cmd ) -- -- special scripting for table with unique keys -- if (@fhasnonpkuniquekeys = 1) begin select @cmd = N' if (@error in (2601, 2627)) begin ' + N'-- ' + N'-- Unique key violation ' + N'-- case 16 : rows with OLD_PK does not exist and row with NEW_UNK exists ' + N'-- generate delete compensating action with OLD_PK' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- insert compensating action with rows that qualify the NEW_UNKEYS ' + N'-- select @cftcase = 16 end' insert into #proctext(procedure_text) values( @cmd ) end select @cmd = N' end end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' else begin ' + N'-- ' + N'-- PK update is being done ' + N'-- Now find the type of conflict ' + N'-- select @cftcase = 0' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using OLD_PK -- select @cmd = N' if exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0 insert into #proctext(procedure_text) values( N' )') -- -- continue scripting -- select @cmd = N' begin ' + N'-- ' + N'-- row with OLD_PK exists ' + N'-- generate delete compensating action with OLD_PK + ' + N'-- insert compensating action with OLD_PK ' + N'-- select @cftcase = 14 end' insert into #proctext(procedure_text) values( @cmd ) -- -- script the if exists code using NEW_PK -- select @cmd = N' if exists (select * from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0 insert into #proctext(procedure_text) values( N' )') -- -- continue scripting -- select @cmd = N' begin ' + N'-- ' + N'-- row with NEW_PK exists ' + N'-- case 15: rows with NEW_PK and OLD_PK exist ' + N'-- generate delete compensating actions with OLD_PK, NEW_PK + ' + N'-- insert compensating actions with OLD_PK, NEW_PK' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- case 16: row with NEW_PK exists and OLD_PK does not exist ' + N'-- generate delete compensating action with OLD_PK, NEW_PK + ' + N'-- insert compensating action with NEW_PK ' + N'-- select @cftcase = case when (@cftcase = 14) then 15 else 16 end end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' else begin ' + N'-- ' + N'-- row with NEW_PK does not exists ' + N'-- case 12 : no existing rows with OLD_PK or NEW_PK ' + N'-- generate delete compensating action with OLD_PK, NEW_PK ' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' ' + N'-- case 17 : row with OLD_PK exist and NEW_PK does not exist ' + N'-- generate delete compensating action with OLD_PK, NEW_PK + ' + N'-- insert compensating action with OLD_PK ' + N'-- select @cftcase = case when (@cftcase = 0) then 12 else 17 end end ' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' end end' insert into #proctext(procedure_text) values( @cmd ) -- -- continue scripting -- select @cmd = N' if (@cftcase in (0, 1, 11, 12, 13, 14, 15, 16, 17)) begin ' + N'-- ' + N'-- generation of delete compensating command with OLD_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- generate delete compensating cmd with OLD_PK -- select @cmd = N' select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + ' insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'del' -- -- script the sending command -- exec sp_MSscript_compensating_send @pubid, @artid, 0, 1 -- -- continue scripting -- select @cmd = N' end if (@cftcase in (1, 12, 15, 16, 17)) begin ' + N'-- ' + N'-- generation of delete compensating command with NEW_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- generate delete compensating cmd with NEW_PK -- select @cmd = N' select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + ' insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins' -- -- script the sending command -- exec sp_MSscript_compensating_send @pubid, @artid, 0, 1 -- -- continue scripting -- select @cmd = N' end if (@cftcase in (0, 1, 11, 14, 15, 17)) begin ' + N'-- ' + N'-- generate and send insert compensating command with OLD_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- script compensating insert with OLD_PK -- exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 1, 0 -- -- continue scripting -- select @cmd = N' end if (@cftcase in (15, 16)) begin ' + N'-- ' + N'-- generate and send insert compensating command with NEW_PK ' + N'--' insert into #proctext(procedure_text) values( @cmd ) -- -- script compensating insert with NEW_PK -- exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 0, 0 -- -- continue with scripting -- select @cmd = N' end select @retcode = 0 end' insert into #proctext(procedure_text) values( @cmd ) -- -- all done -- return 0 END go exec dbo.sp_MS_marksystemobject sp_MSscript_update_pubwins go -------------------------------------------------------------------------------- --. sp_MSscript_compensating_insert -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_compensating_insert') drop procedure sp_MSscript_compensating_insert go raiserror('Creating procedure sp_MSscript_compensating_insert', 0,1) go create procedure sp_MSscript_compensating_insert ( @publication sysname, @article sysname, @objid int, @columns binary(32), @proctype int = 1, -- 0 = use new_pk, 1 = use old_pk @fdodeclare bit = 1 -- 0 = do not script declares for non PK unique key processing ) AS BEGIN declare @cmd nvarchar(4000) ,@artid int ,@pubid int ,@dest_table sysname ,@dest_owner nvarchar(260) ,@colname sysname ,@ccoltype sysname ,@this_col int ,@rc int ,@num_col int ,@qualname nvarchar(540) ,@cast_str nvarchar(4000) ,@column_string nvarchar(4000) ,@ins_cmd nvarchar(255) ,@startoffset int ,@setprefix bit ,@commandlen int ,@fragmentlen int ,@collen int ,@first_time bit ,@fullcastlen int ,@splitlen int ,@pkcolumns varbinary(32) ,@fhasnonpkuniquekeys int declare @pkfetch table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- -- initialize the vars we will use -- select @pubid = pubid from syspublications where name = @publication select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner, @ins_cmd = ins_cmd from sysarticles where name = @article and pubid = @pubid select @dest_owner = case when (@dest_owner IS NULL) then N'' else quotename(@dest_owner) + N'.' end ,@fhasnonpkuniquekeys = 0 exec sp_MSget_qualified_name @objid, @qualname OUTPUT -- -- Do we have non PK unique keys -- exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid if (@fhasnonpkuniquekeys = 1) begin -- -- We have to generate commands based on where it was confict with PK or with other -- unique keys - so we will declare a cursor and walk through all the rows on publisher -- that could have conflicts with the subscriber row. For each row (PK) we will now perform -- compensating delete of non PK unique keys and then an compensating insert -- declare @cmd2 nvarchar(4000) ,@cmd3 nvarchar(4000) ,@spacer nvarchar(5) ,@typestring sysname ,@art_col int ,@isset int declare @pkvars table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) declare @pkcols table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null) -- -- build some strings for PK columns and PK variables (@pkc1..) -- exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output select @cmd = N'' ,@cmd2 = N'' ,@cmd3 = N'' ,@spacer = N'' ,@art_col = 1 declare #hccolid cursor local fast_forward for select colid, name from syscolumns where id = @objid order by colid asc open #hccolid fetch #hccolid into @this_col, @colname while (@@fetch_status != -1) begin exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns if @isset != 0 and (@colname is not null) begin exec dbo.sp_gettypestring @objid, @this_col, @typestring output select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring ,@cmd2 = @cmd2 + @spacer + quotename(@colname) ,@cmd3 = @cmd3 + @spacer + N'@pkc' + convert( nvarchar, @art_col ) select @art_col = @art_col + 1 ,@spacer = N',' if len( @cmd ) > 3000 begin insert into @pkvars(procedure_text) values( @cmd ) select @cmd = N'' end if len( @cmd2 ) > 3000 begin insert into @pkcols(procedure_text) values( @cmd2 ) select @cmd2 = N'' end if len( @cmd3 ) > 3000 begin insert into @pkfetch(procedure_text) values( @cmd3 ) select @cmd3 = N'' end end fetch #hccolid into @this_col, @colname end close #hccolid deallocate #hccolid if len(@cmd) > 0 insert into @pkvars(procedure_text) values( @cmd ) if len(@cmd2) > 0 insert into @pkcols(procedure_text) values( @cmd2 ) if len(@cmd3) > 0 insert into @pkfetch(procedure_text) values( @cmd3 ) -- -- script the PK variable declare now -- if (@fdodeclare = 1) begin select @cmd = N' declare ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from @pkvars order by c1 asc end -- -- script the cursor declare now -- select @cmd = N' declare #hccompins cursor local fast_forward for select distinct ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from @pkcols order by c1 asc select @cmd = N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) if (@proctype = 1) begin exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid ,@columns = @columns ,@prefix = N'@c' ,@suffix = N'_old' ,@mode = 5 end else begin exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid ,@columns = @columns ,@prefix = N'@c' ,@mode = 5 end -- -- script the cursor open and fetch -- select @cmd = N' open #hccompins fetch #hccompins into ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from @pkfetch order by c1 asc select @cmd = N' while (@@fetch_status != -1) begin ' insert into #proctext(procedure_text) values( @cmd ) -- -- The table has unique keys other than PK We will issue a compensating -- DELETE command to clear any rows that already have values for the -- unique key columns - the subsequent compensating INSERT has to succeed. -- We will restore the current view of the publisher on to the subscriber -- if Subscriber had a rows that were different from publisher - then they will -- be resolved during the Queue reader run. So we are covered -- select @cmd = N' ' + '-- ' + '-- Issue a delete command for unique keys ' + '-- ' insert into #proctext(procedure_text) values( @cmd ) select @cmd = N' select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + ' insert into #proctext(procedure_text) values( @cmd ) exec dbo.sp_replscriptuniquekeywhereclause @tabid = @objid ,@columns = @columns ,@mode = 4 select @cmd = N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) exec @rc = sp_scriptpkwhereclause @src_objid = @objid ,@pkcolumns = @pkcolumns ,@prefix = N'@pkc' ,@artcolumns = @columns exec sp_MSscript_compensating_send @pubid, @artid, 0, 1 select @cmd = N' ' + '-- ' + '-- Issue the compensating insert for this PK row ' + '-- ' insert into #proctext(procedure_text) values( @cmd ) end -- -- The compensating command will be split into one or more -- fragment commands if the length exceeds 3450 characters in length -- (to accomodate compensating server/db names) -- For correctly estimating the length of the compensating command -- we have to take the max column length of the data into consideration along -- with the scripting command length -- -- -- use the insert command if available -- select @commandlen = 0 ,@setprefix = 1 if (@ins_cmd = N'SQL') begin select @cmd = N' select @cmd = ''INSERT INTO ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N''' + '' SELECT '' + ' end else begin select @cmd = N' select @cmd = ''EXEC ' + substring(@ins_cmd, 5, len(@ins_cmd) - 4) + N' '' + ' end insert into #proctext(procedure_text) values( @cmd ) select @commandlen = @commandlen + len(@cmd) select @num_col = 0 DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR select colid, length from syscolumns where id = @objid order by colid asc OPEN hCColid FETCH hCColid INTO @this_col, @collen WHILE (@@fetch_status != -1) begin exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 1, @colname output, @ccoltype output if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1) begin if rtrim(@ccoltype) not like N'timestamp' begin select @num_col = @num_col + 1 -- -- Compute the command fragment length needed for this column -- based on the coltype -- if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('ntext','text','image')) begin -- -- For compensating commands we have to include the text and image data -- as the custom procs used by Distribution process expects them - as it -- done for regular transactional replication - but we will only send NULLs -- as it is not possible to ascertain the size of the data during the generation -- select @cast_str = N' ''null'' ' select @fullcastlen = len(@cast_str) select @fragmentlen = @fullcastlen + 4 + @collen end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar')) begin if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar')) select @collen = (@collen / 2) select @cast_str = case when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar')) then N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') ' else N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') ' end select @fullcastlen = len(@cast_str) select @fragmentlen = @fullcastlen + 4 + @collen end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) begin -- -- each byte has 2 nibbles - we need a char to represent each nibble -- select @collen = @collen * 2 select @cast_str = N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' + quotename(@colname) + N',1,0) collate database_default, ''null'') ' select @fullcastlen = len(@cast_str) select @fragmentlen = @fullcastlen + 4 + @collen + 2 end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric')) begin select @collen = 40 select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') ' select @fragmentlen = len(@cast_str) + @collen end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney')) begin select @collen = 40 select @cast_str = N' ISNULL(CONVERT(nvarchar(40),' + quotename(@colname) + N',2), ''null'') ' select @fragmentlen = len(@cast_str) + @collen end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier') begin select @collen = 40 select @cast_str = N' ISNULL('''''''' + CAST(' + quotename(@colname) + N' as nvarchar(40)) + '''''''', ''null'') ' select @fragmentlen = len(@cast_str) + @collen end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime')) begin select @collen = 40 select @cast_str = N' ISNULL('''''''' + CONVERT(nvarchar(40), ' + quotename(@colname) + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + quotename(@colname) + N', 114) + '''''''', ''null'') ' select @fragmentlen = len(@cast_str) + @collen end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant') begin -- -- need to revisit this later -- select @cast_str = N' ISNULL(master.dbo.fn_sqlvarbasetostr(' + quotename(@colname) + N' ) collate database_default, ''null'') ' select @fragmentlen = len(@cast_str) + @collen end else begin select @collen = 40 select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') ' select @fragmentlen = len(@cast_str) + @collen end -- -- for fixed datatypes - we will not split the data at all we will -- flush the command script and continue -- for varying/large datatypes, we will have to split data if necessary -- if ((lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar','binary','varbinary')) and (@fragmentlen + @commandlen > 3450)) begin -- -- the column length is too big, we have to break the data string -- initialize -- if (@num_col = 1) begin select @column_string = N' ' end else begin select @column_string = N' + '','' + ' end -- -- use substring to break the string value in the -- compensating command -- select @first_time = 1 ,@startoffset = 1 while (@collen > 0) begin select @splitlen = case when ((@first_time = 1) or (@collen > 3450)) then (3450 - @commandlen - 30 - @fullcastlen) else @collen end if (@splitlen < 1) begin -- -- we have overcompensated the splitlen -- set to half of the column length -- select @splitlen = @collen / 2 end -- -- Do we need to put quotes (many datatypes need it) -- if (@first_time = 1) begin if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar')) select @column_string = case when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar')) then @column_string + N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr( ' else @column_string + N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr( ' end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) select @column_string = @column_string + N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' end else begin if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar')) select @column_string = N' + ISNULL(master.dbo.fn_MSgensqescstr( ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) select @column_string = @column_string + N' + ISNULL(master.dbo.fn_varbintohexsubstring(0,' end -- -- prepare the substring script -- if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar')) select @cast_str = N'SUBSTRING(' + quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' + cast(@splitlen as nvarchar) + N')' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) select @cast_str = quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' + cast((@splitlen/2) as nvarchar) if (@first_time = 1) begin select @cast_str = @cast_str + N') collate database_default, ''null'') ' ,@first_time = 0 end else begin if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar')) begin -- -- for strings the last fragment needs the single -- quote to be added for the string -- select @cast_str = @cast_str + N') collate database_default ' select @cast_str = case when (@collen - @splitlen < 1) then @cast_str + N'+ '''''''', '''') ' else @cast_str + N', '''') ' end end else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) select @cast_str = @cast_str + N') collate database_default, '''') ' end select @column_string = @column_string + @cast_str insert into #proctext(procedure_text) values( @column_string ) if (@fragmentlen + @commandlen > 3450) begin select @cmd = N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) -- -- script the where clause -- if (@fhasnonpkuniquekeys = 1) begin -- -- Non PK unique keys -- we are in the cursor for qualifying row -- exec dbo.sp_scriptpkwhereclause @src_objid = @objid ,@pkcolumns = @pkcolumns ,@prefix = N'@pkc' ,@artcolumns = @columns end else begin -- -- only PK unique key -- if (@proctype = 1) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del' else exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins' end -- -- Script the compensating send -- exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix if (@setprefix = 1) select @setprefix = 0 select @cmd = N' select @cmd = N''''' insert into #proctext(procedure_text) values( @cmd ) select @commandlen = 0 end else select @commandlen = @commandlen + len(@column_string) -- -- update vars for next round -- select @collen = @collen - @splitlen ,@column_string = N'' ,@startoffset = case when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) then (@splitlen/2) + @startoffset else @splitlen + @startoffset end select @fragmentlen = @fullcastlen + 4 + @collen end -- -- we done with this column now -- skip processing further and continue -- select @commandlen = @commandlen + len(@column_string) end else begin -- -- Handling general fixed type column cases -- if (@num_col = 1) begin select @column_string = N' ' + @cast_str end else begin select @column_string = N' + '','' + ' + @cast_str end -- -- check if we need to flush the command first -- if (@fragmentlen + len(@column_string) + @commandlen > 3450) begin -- -- send this compensating command first -- select @cmd = N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) -- -- script the where clause -- if (@fhasnonpkuniquekeys = 1) begin -- -- Non PK unique keys -- we are in the cursor for qualifying row -- exec dbo.sp_scriptpkwhereclause @src_objid = @objid ,@pkcolumns = @pkcolumns ,@prefix = N'@pkc' ,@artcolumns = @columns end else begin -- -- only PK unique key -- if (@proctype = 1) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del' else exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins' end -- -- Script the compensating send -- exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix if (@setprefix = 1) select @setprefix = 0 select @cmd = N' select @cmd = N'' ''' insert into #proctext(procedure_text) values( @cmd ) select @commandlen = 0 end -- -- script out the column string -- insert into #proctext(procedure_text) values( @column_string ) -- -- if we are processing sql_variants, flush the command again -- if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant') begin -- -- send this compensating command first -- select @cmd = N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) -- -- script the where clause -- if (@fhasnonpkuniquekeys = 1) begin -- -- Non PK unique keys -- we are in the cursor for qualifying row -- exec dbo.sp_scriptpkwhereclause @src_objid = @objid ,@pkcolumns = @pkcolumns ,@prefix = N'@pkc' ,@artcolumns = @columns end else begin -- -- only PK unique key -- if (@proctype = 1) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del' else exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins' end -- -- Script the compensating send -- exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix if (@setprefix = 1) select @setprefix = 0 select @cmd = N' select @cmd = N'' ''' insert into #proctext(procedure_text) values( @cmd ) select @commandlen = 0 end else select @commandlen = @commandlen + @fragmentlen + len(@column_string) end end end -- -- process the next column -- FETCH hCColid INTO @this_col, @collen end CLOSE hCColid DEALLOCATE hCColid -- -- Check if we need to flush the command one more time (final) -- if (@commandlen > 0) begin -- -- send the last fragment of the command -- select @cmd = N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd ) -- -- script the where clause -- if (@fhasnonpkuniquekeys = 1) begin -- -- Non PK unique keys -- we are in the cursor for qualifying row -- exec dbo.sp_scriptpkwhereclause @src_objid = @objid ,@pkcolumns = @pkcolumns ,@prefix = N'@pkc' ,@artcolumns = @columns end else begin -- -- only PK unique key -- if (@proctype = 1) exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del' else exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins' end -- -- Script the compensating send -- exec sp_MSscript_compensating_send @pubid, @artid, 0, @setprefix end -- -- More scripting for non PK unique key case -- if (@fhasnonpkuniquekeys = 1) begin -- -- script the cursor fetch -- select @cmd = N' fetch #hccompins into ' insert into #proctext(procedure_text) values( @cmd ) insert into #proctext(procedure_text) select procedure_text from @pkfetch order by c1 asc -- -- script the cursor close and deallocate -- select @cmd = N' end close #hccompins deallocate #hccompins ' insert into #proctext(procedure_text) values( @cmd ) end -- -- all done -- return 0 END go exec dbo.sp_MS_marksystemobject sp_MSscript_compensating_insert go -------------------------------------------------------------------------------- --. sp_MSscript_endproc -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSscript_endproc') drop procedure sp_MSscript_endproc go raiserror('Creating procedure sp_MSscript_endproc', 0,1) go create procedure sp_MSscript_endproc ( @objid int, @op_type varchar(3) = 'ins', -- 'ins', 'upd', 'del' @columns binary(32), @outvars nvarchar(4000), @queued_pub bit = 0 ) as BEGIN declare @cmd nvarchar(4000) declare @qualname nvarchar(512) exec sp_MSget_qualified_name @objid, @qualname OUTPUT -- -- start scripting -- select @cmd = N' ' + N'-- ' + N'-- decide the return code ' + N'-- if (@execution_mode = @immediate) begin if @error != 0 return -1 -- Return special code to indicate the subscriber row needs to be -- refreshed. if @rowcount = 0 return 5 end' insert into #proctext(procedure_text) values(@cmd) -- -- operation specific stuff -- if (@queued_pub = 1) begin if (@op_type = 'ins') begin select @cmd = N' if (@execution_mode = @QFirstPass) begin if (@rowcount = 0) begin if (@error in (547, 2601, 2627)) return 2 -- insert conflict else return -1 -- error end end' end else if (@op_type = 'upd') begin select @cmd = N' if (@execution_mode = @QFirstPass) begin if (@rowcount = 0) begin if (@error in (0, 547, 2601, 2627)) return 1 -- update conflict else return -1 -- error end end' end else if (@op_type = 'del') begin select @cmd = N' if (@execution_mode = @QFirstPass) begin if (@rowcount = 0) begin if (@error in (0, 547)) return 3 -- delete conflict else return -1 -- error end end' end insert into #proctext(procedure_text) values(@cmd) -- -- continue with scripting -- select @cmd = N' if (@execution_mode in (@QPubWins, @QSubWins)) begin if (@@error != 0 or @retcode != 0) return -1 -- error end ' insert into #proctext(procedure_text) values(@cmd) end -- -- if we have output vars to assign do it now -- if (@outvars is not null) begin if @op_type = 'upd' begin -- -- Script out pk var assigment that used in sp_MSscript_where_clause -- exec dbo.sp_MSscript_pkvar_assignment @objid, @columns, 1 insert into #proctext(procedure_text) values(N' ') end select @cmd = N' select ' + @outvars + N' from ' + @qualname insert into #proctext(procedure_text) values( @cmd) insert into #proctext(procedure_text) values( N' ') if (@op_type = 'ins') exec dbo.sp_MSscript_where_clause @objid, @columns, 'new pk', null, 4 else if (@op_type = 'upd') exec dbo.sp_MSscript_where_clause @objid, @columns, 'old pk', null, 4 end -- -- Final part of the proc -- select @cmd = N' ' + N'-- ' + N'-- past all checks ' + N'-- return 0 END ' insert into #proctext(procedure_text) values(@cmd) -- -- all done -- return 0 END go exec dbo.sp_MS_marksystemobject sp_MSscript_endproc go -------------------------------------------------------------------------------- --. sp_repltablehasnonpkuniquekey -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_repltablehasnonpkuniquekey') drop procedure sp_repltablehasnonpkuniquekey go raiserror('Creating procedure sp_repltablehasnonpkuniquekey',0,-1) go create procedure sp_repltablehasnonpkuniquekey ( @tabid int -- id of the table ) as begin set nocount on declare @retcode int -- -- security check - should be dbo or sysadmin -- exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR != 0 or @retcode != 0 return (1) -- -- process if the object is a table and has index -- if (ObjectProperty(@tabid, 'IsTable') = 1) and (ObjectProperty(@tabid, 'TableHasIndex') = 1) begin -- -- Set return flag if it is Unique key but not PK -- if exists (select indid from sysindexes where id = @tabid and indid > 0 and indid < 255 and (status & 2) != 0 and (status & 2048) = 0 ) begin select @retcode = 1 end end -- -- all done -- return @retcode end go exec sp_MS_marksystemobject sp_repltablehasnonpkuniquekey go -------------------------------------------------------------------------------- --. sp_replscriptuniquekeywhereclause -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_replscriptuniquekeywhereclause') drop procedure sp_replscriptuniquekeywhereclause go raiserror('Creating procedure sp_replscriptuniquekeywhereclause', 0,1) go create procedure sp_replscriptuniquekeywhereclause ( @tabid int -- id of the table ,@columns binary(32) -- column map for the article ,@prefix nvarchar(10) = '@c' -- prefix for the scripted column variables ,@suffix nvarchar(10) = null -- suffix for the scripted column variables ,@mode tinyint -- 1 = insert custom proc, 2 = upd custom proc non PK, 3 = upd custom proc PK only 4 = compensating delete, 5 = compensating insert cursor declare ,@paramcount int = null -- Total number of parameters - needed for mode = 2 and 3 ) as begin set nocount on declare @retcode int ,@indid int ,@indstatus int ,@indkey int ,@qualname nvarchar(512) ,@colname sysname ,@var sysname ,@artcol int ,@thiscol int ,@cmd nvarchar(4000) ,@findexstarted bit ,@fisfirstindex bit -- -- constants -- ,@modeinscustproc tinyint ,@modeupdcustprocnonpk tinyint ,@modeupdcustprocpkonly tinyint ,@modedelcompensating tinyint ,@modeinscompensatingcursordeclare tinyint -- -- initialize -- select @modeinscustproc = 1 ,@modeupdcustprocnonpk = 2 ,@modeupdcustprocpkonly = 3 ,@modedelcompensating = 4 ,@modeinscompensatingcursordeclare = 5 -- -- security check - should be dbo or sysadmin -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error != 0 or @retcode != 0 return (1) -- -- process if the object is a table and has index -- if (ObjectProperty(@tabid, 'IsTable') != 1) or (ObjectProperty(@tabid, 'TableHasIndex') != 1) return (1) -- -- Get the qualified name of the table -- exec @retcode = sp_MSget_qualified_name @tabid, @qualname OUTPUT if @@error != 0 or @retcode != 0 or @qualname is null return (1) -- -- @columns cannot be null -- if (@columns is null) return (1) -- -- Check @mode -- if (@mode not in (@modeinscustproc, @modeupdcustprocnonpk, @modeupdcustprocpkonly, @modedelcompensating, @modeinscompensatingcursordeclare)) begin return (1) end -- -- validate @paramcount -- if ((@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) and (@paramcount is null)) begin return (1) end -- -- enumerate all the unique indices -- The scripting will be done as follows : -- where (ui1k1 = @cx and ui1k2 = @cy ...) or (u2k1 = @cz and ...) ... -- If we are scripting for the cursor declare in insert compensating then it will be as follows: -- where (ui1k1 = @cx or ui1k2 = @cy ...) or (u2k1 = @cz or ...) ... -- select @cmd = case when (@mode = @modedelcompensating) then N' '' where ' else N' where ' end ,@findexstarted = 0 ,@fisfirstindex = 1 declare #hcindid cursor local fast_forward for select indid, status from sysindexes where id = @tabid and (status & 2) != 0 and indid > 0 and indid < 255 order by indid asc open #hcindid fetch #hcindid into @indid, @indstatus while (@@fetch_status != -1) begin -- -- If we are in @modedelcompensating or @modeupdcustprocnonpk mode skip processing the PK index -- If we are in @modeupdcustprocpkonly mode skip processing the non PK index -- if ((@mode in (@modeupdcustprocnonpk,@modedelcompensating)) and (@indstatus & 2048) != 0) or ((@mode = @modeupdcustprocpkonly) and (@indstatus & 2048) = 0) begin -- -- fetch next unique index -- fetch #hcindid into @indid, @indstatus continue end -- -- Enumerate the keys in this index -- select @indkey = 1 while (@indkey <= 16) begin -- -- get the column name for the key -- select @colname = index_col(@qualname, @indid, @indkey) if (@colname is null) break -- -- check if this column is enabled for replication -- select @artcol = 0 exec dbo.sp_MSget_col_position @tabid, @columns, @colname, NULL, @artcol output, 0, NULL, @thiscol output if (@artcol > 0) begin -- -- check if we are scripting the first key for this index -- if (@findexstarted = 1) begin select @cmd = case when (@mode = @modedelcompensating) then @cmd + N' + '' and ' when (@mode = @modeinscompensatingcursordeclare) then @cmd + N' or ' else @cmd + N' and ' end end else begin -- -- check if we are scripting the first index. -- if (@fisfirstindex = 0) begin select @cmd = @cmd + N' or ' end else begin select @fisfirstindex = 0 end -- -- set @findexstarted while processing the first key -- select @findexstarted = 1 select @cmd = @cmd + N' ( ' end -- -- script this column -- if (@mode = @modedelcompensating) begin -- -- scripting a compensating command - we are building a dynamic string -- declare @ccoltype sysname select @cmd = @cmd + quotename(@colname) ,@var = quotename(@colname) exec dbo.sp_MSget_colinfo @tabid, @thiscol, @columns, 0, NULL, @ccoltype output if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar') select @cmd = @cmd + N' = '' + ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''', ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar') select @cmd = @cmd + N' = '' + ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''', ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char') select @cmd = @cmd + N' = '' + ISNULL('''''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''', ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar') select @cmd = @cmd + N' = '' + ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''', ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) select @cmd = @cmd + N' = '' + ISNULL(master.dbo.fn_varbintohexstr(' + @var + N') collate database_default, ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric')) select @cmd = @cmd + N' = '' + ISNULL(CAST(' + @var + N' as nvarchar), ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney')) select @cmd = @cmd + N' = '' + ISNULL(CONVERT(nvarchar(40),' + @var + N', 2), ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier') select @cmd = @cmd + N' = '' + ISNULL('''''''' + CAST(' + @var + N' as nvarchar(40)) + '''''''', ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime')) select @cmd = @cmd + N' = '' + ISNULL('''''''' + CONVERT(nvarchar(40), ' + @var + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @var + N', 114) + '''''''', ''null'') ' else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant') select @cmd = @cmd + N' = '' + ISNULL(master.dbo.fn_sqlvarbasetostr(' + @var + N' ) collate database_default, ''null'') ' else select @cmd = @cmd + N' = '' + ISNULL(CAST(' + @var + N' as nvarchar), ''null'') ' end else begin -- -- scripting for custom procs - static script -- select @var = case when (@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) then @prefix + cast((@artcol + @paramcount/2) as nvarchar(10)) else @prefix + cast(@artcol as nvarchar(10)) end if (@suffix is not null) select @var = @var + @suffix -- -- Does the column allow NULLs -- if (columnproperty( @tabid , @colname , 'AllowsNull' ) = 1) begin -- -- static scripting should handle NULL valued column -- ((<@var> is null and <colname> is null) or (<@var> is not null and <colname> = <@var>)) -- select @cmd = @cmd + N'((' + @var + N' is null and ' + quotename(@colname) + N' is null) or (' + @var + N' is not null and ' + quotename(@colname) + N' = ' + @var + N'))' end else begin -- -- static scripting does not need to check for NULL values -- <colname> = <@var> -- select @cmd = @cmd + quotename(@colname) + N' = ' + @var end -- -- special processing for @modeupdcustprocnonpk -- if (@mode = @modeupdcustprocnonpk) begin select @cmd = @cmd + N' and ' + @prefix + cast((@artcol + @paramcount/2) as nvarchar(10)) if (@suffix is not null) select @cmd = @cmd + @suffix select @cmd = @cmd + N' != ' + @prefix + cast(@artcol as nvarchar(10)) if (@suffix is not null) select @cmd = @cmd + @suffix end end -- -- transfer command string to table if too large -- if (len(@cmd) > 3000) exec dbo.sp_MSflush_command @cmd output, 1, 0 end -- -- get the next key for the index -- select @indkey = @indkey + 1 end -- -- done with current index -- select @findexstarted = 0 ,@cmd = case when (@mode = @modedelcompensating) then @cmd + N' + '' ) ' else @cmd + N' ) ' end -- -- fetch next unique index -- fetch #hcindid into @indid, @indstatus end close #hcindid deallocate #hcindid -- -- Final flush -- if (@mode = @modedelcompensating) select @cmd = @cmd + N'''' if (len(@cmd) > 0) exec dbo.sp_MSflush_command @cmd output, 1, 0 -- -- all done -- return 0 end go exec sp_MS_marksystemobject sp_replscriptuniquekeywhereclause go -------------------------------------------------------------------------------- --. sp_MSgettrancftsrcrow -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgettrancftsrcrow') drop procedure sp_MSgettrancftsrcrow go raiserror('Creating procedure sp_MSgettrancftsrcrow',0,-1) go create procedure sp_MSgettrancftsrcrow ( @tran_id sysname, @row_id sysname, @conflict_table nvarchar(256), @is_subscriber bit, @is_debug bit=0 ) as begin set nocount on declare @decllist nvarchar(4000) ,@sellist nvarchar(4000) ,@wherelist nvarchar(4000) ,@cmd nvarchar(4000) ,@cmdrow nvarchar(4000) ,@srctable sysname ,@srctabid int ,@srcowner sysname ,@columns binary(32) ,@indid int ,@indkey int ,@key sysname ,@this_col int ,@col sysname ,@typestring nvarchar(60) ,@dbname sysname ,@retcode smallint ,@unqualified_cft_tab sysname ,@startoffset int -- -- validate -- if ((@tran_id is null) or (@row_id is null) or (@conflict_table is null) or (@is_subscriber is null)) begin raiserror('sp_MSgettrancftsrcrow(debug): @tran_id,@row_id,@conflict_table,@is_subscriber cannot be null', 16, 1) return (1) end -- -- check if the conflict table is owner qualified -- select @startoffset = charindex(N'].[', @conflict_table, 0) select @unqualified_cft_tab = case when (@startoffset > 0) then substring(@conflict_table, @startoffset + 2, len(@conflict_table) - @startoffset - 1) else quotename(@conflict_table) end -- -- get the source table info -- if (@is_subscriber = 1) begin select @srcowner = owner, @srctable = dest_table, @srctabid = OBJECT_ID(dest_table), @columns = columns from MSsubscription_articles where quotename(cft_table) = @unqualified_cft_tab end else begin select @srcowner = user_name(OBJECTPROPERTY(objid,'OwnerId')), @srctable = OBJECT_NAME(objid), @srctabid = objid, @columns = columns from sysarticles a join sysarticleupdates b on a.pubid = b.pubid and a.artid = b.artid where b.conflict_tableid = OBJECT_ID(@conflict_table) end -- -- create code for the following : -- select the row of conflict with given tranid and insertdate -- retrieve the values of the PK/UI columns for the source table from this row in cft_table -- select all columns from source table using the values in a where clause for PK/UI -- -- -- PK/UI check for source table -- exec @indid = dbo.sp_MStable_has_unique_index @srctabid if (@indid = 0) begin raiserror('sp_MSgettrancftsrcrow(debug):source table %s does not have unique index', 16, 1, @srctable) return (1) end -- -- create temp tables -- create table #decltext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null) create table #seltext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null) create table #wheretext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null) -- -- walk through each column in PK/UI and build parts of code -- select @indkey = 1 while (@indkey <= 16) begin select @key = index_col(@srctable, @indid, @indkey) if (@key is null) begin select @indkey = 16 end else begin -- -- get the column index in the source table for this index key -- exec dbo.sp_MSget_col_position @srctabid, @columns, @key, @col output, @this_col output -- -- get the typestring for this column in source table -- exec dbo.sp_gettypestring @srctabid, @this_col, @typestring OUTPUT -- -- build command strings -- if (@decllist is NULL) select @decllist = N'declare @' + @col + N' ' + @typestring else select @decllist = N' ,@' + @col + N' ' + @typestring if (@sellist is NULL) select @sellist = N'select @' + @col + N' = ' + quotename(@key) else select @sellist = N' ,@' + @col + N' = ' + quotename(@key) if (@wherelist is NULL) select @wherelist = N'where ' + quotename(@key) + N' = @' + @col else select @wherelist = N' and ' + quotename(@key) + N' = @' + @col -- -- store them in the temp tables -- insert into #decltext(cmdtext) values(@decllist) insert into #seltext(cmdtext) values(@sellist) insert into #wheretext(cmdtext) values(@wherelist) end select @indkey = @indkey + 1 end -- -- Now put all the code in order in the codetext -- if exists (select * from sysobjects where name = 'MSsrcrow_codetext') drop table MSsrcrow_codetext create table MSsrcrow_codetext ( step int identity NOT NULL, cmdtext nvarchar(4000) NULL) insert into MSsrcrow_codetext(cmdtext) select cmdtext from #decltext order by c1 insert into MSsrcrow_codetext(cmdtext) values (N' ') insert into MSsrcrow_codetext(cmdtext) select cmdtext from #seltext order by c1 select @cmd = N' from ' if (@startoffset > 0) select @cmd = @cmd + @conflict_table else select @cmd = @cmd + quotename(@srcowner) + N'.' + @unqualified_cft_tab select @cmd = @cmd + N' where tranid = ''' + @tran_id + ''' and qcfttabrowid = ''' + @row_id + ''' ' insert into MSsrcrow_codetext(cmdtext) values (@cmd) select @cmd = N'select * from ' + quotename(@srcowner) + N'.' + quotename(@srctable) + N' ' insert into MSsrcrow_codetext(cmdtext) values (@cmd) insert into MSsrcrow_codetext(cmdtext) select cmdtext from #wheretext order by c1 -- -- now execute the code we just built -- if (@is_debug = 0) begin -- -- Build 139: -- NOTE xp_execresultset should work here but does not -- return for a long time. Using exec() - should revisit -- this for more stable builds -- declare #srccursor cursor local FAST_FORWARD FOR select cmdtext from MSsrcrow_codetext order by step FOR READ ONLY select @cmd = N' ' select @dbname = db_name() open #srccursor fetch #srccursor into @cmdrow while (@@FETCH_STATUS = 0) begin select @cmd = @cmd + @cmdrow fetch #srccursor into @cmdrow end close #srccursor deallocate #srccursor execute(@cmd) if (@@error != 0) begin raiserror('sp_MSgettrancftsrcrow(debug): execute() failed for [%s] in db [%s] ', 16, 1, @cmd, @dbname) return (1) end end else select cmdtext from MSsrcrow_codetext order by step -- -- all done -- drop table MSsrcrow_codetext return 0 end go exec dbo.sp_MS_marksystemobject sp_MSgettrancftsrcrow go grant execute on dbo.sp_MSgettrancftsrcrow to public go -------------------------------------------------------------------------------- --. sp_check_for_sync_trigger -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_script_synctran_commands') drop procedure sp_script_synctran_commands go raiserror('Creating procedure sp_script_synctran_commands', 0,1) GO CREATE PROCEDURE sp_script_synctran_commands( @publication sysname, /* publication name */ @article sysname = 'all' /* article name, all means all article */ ) AS begin declare @retcode int -- -- security check -- exec @retcode = dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 begin return (1) end -- -- Generate the scripts by calling internal SP -- exec @retcode = dbo.sp_MSget_synctran_commands @publication = @publication, @article = @article, @command_only = 1 if @retcode <> 0 or @@error <> 0 return (1) end go EXEC dbo.sp_MS_marksystemobject sp_script_synctran_commands GO grant execute on dbo.sp_script_synctran_commands to public go -------------------------------------------------------------------------------- --. sp_replsqlqgetrows -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_replsqlqgetrows') drop procedure sp_replsqlqgetrows go raiserror('Creating procedure sp_replsqlqgetrows', 0,1) go create proc sp_replsqlqgetrows ( @publisher sysname ,@publisherdb sysname ,@publication sysname ) as begin set nocount on declare @retcode int -- -- security check -- exec @retcode = sp_MSreplcheck_subscribe if @@error <> 0 or @retcode <> 0 begin return (1) end -- -- return rows -- if exists (select * from dbo.sysobjects where name = 'MSreplication_queue') begin select tranid, datalen, data, commandtype, insertdate, orderkey, cmdstate from dbo.MSreplication_queue with (READPAST) where UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisherdb and publication = @publication order by orderkey, tranid if (@@error != 0) return 1 end else begin -- -- create empty rowset -- declare @nomesgs TABLE (tranid sysname, datalen int, data varbinary(8000), commandtype int, insertdate datetime, orderkey bigint, cmdstate bit) select * from @nomesgs end -- -- All done -- return 0 end go exec dbo.sp_MS_marksystemobject sp_replsqlqgetrows go grant execute on dbo.sp_replsqlqgetrows to public go -------------------------------------------------------------------------------- --. sp_changesubstatus -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P ' and name = 'sp_changesubstatus') drop procedure sp_changesubstatus go print '' print 'Creating procedure sp_changesubstatus' go CREATE PROCEDURE sp_changesubstatus ( @publication sysname = '%', /* publication name */ @article sysname = '%', /* article name */ @subscriber sysname = '%', /* subscriber name */ @status sysname, /* subscription status */ @previous_status sysname=NULL, /* previous subscription status */ @destination_db sysname = '%', /* destination database name */ @frequency_type int = NULL, @frequency_interval int = NULL, @frequency_relative_interval int = NULL, @frequency_recurrence_factor int = NULL, @frequency_subday int = NULL, @frequency_subday_interval int = NULL, @active_start_time_of_day int = NULL, @active_end_time_of_day int = NULL, @active_start_date int = NULL, @active_end_date int = NULL, @optional_command_line nvarchar(4000) = NULL, @distribution_jobid binary(16) = NULL OUTPUT, @from_auto_sync bit = 0, @ignore_distributor bit = 0, -- Agent offload @offloadagent bit = 0, @offloadserver sysname = NULL, @dts_package_name sysname = NULL, @dts_package_password nvarchar(524) = NULL, @dts_package_location int = 0, @schemastabilityonly int = 0, @distribution_job_name sysname = NULL ) AS SET NOCOUNT ON DECLARE @inactive tinyint DECLARE @subscribed tinyint DECLARE @active tinyint DECLARE @initiated tinyint DECLARE @public tinyint DECLARE @replicate_bit smallint DECLARE @msg nvarchar(255) DECLARE @prevstatid tinyint DECLARE @artid int DECLARE @tabid int DECLARE @srvid smallint DECLARE @statusid tinyint DECLARE @distributor sysname DECLARE @distribdb sysname DECLARE @distproc nvarchar (255) DECLARE @pub_db sysname DECLARE @dest_db sysname DECLARE @sub_name sysname DECLARE @sub_status tinyint DECLARE @sub_ts varbinary (16) DECLARE @non_sql_flag bit DECLARE @qcmd nvarchar (4000) DECLARE @cmd1 nvarchar (255) DECLARE @cmd2 nvarchar (255) DECLARE @cmd3 nvarchar (255) DECLARE @retcode int DECLARE @repl_freq tinyint DECLARE @art_type tinyint DECLARE @proccmd nvarchar(255) DECLARE @procnum smallint DECLARE @finished_real bit DECLARE @finished_virtual bit DECLARE @virtual_id smallint DECLARE @immediate_sync bit DECLARE @enabled_for_internet bit DECLARE @allow_anonymous bit DECLARE @subscription_type int DECLARE @xact_seqno binary(10) DECLARE @sync_type tinyint DECLARE @automatic tinyint DECLARE @bcp_char tinyint DECLARE @concurrent_char tinyint DECLARE @art_change bit declare @login_name sysname DECLARE @pubid int DECLARE @syncinit_lsn binary(10) DECLARE @f_syncstat_posted bit -- synctran DECLARE @update_mode tinyint DECLARE @art_name sysname declare @synctran tinyint declare @no_distproc bit declare @loopback_detection bit /* ** Initializations. */ select @synctran = 1 SELECT @automatic = 1 SELECT @inactive = 0 /* Const: subscription status 'inactive' */ SELECT @subscribed = 1 /* Const: subscription status 'subscribed' */ SELECT @active = 2 /* Const: subscription status 'active' */ SELECT @initiated = 3 /* Const: subscription status 'initiated' */ SELECT @public = 0 /* Const: publication status 'public' */ SELECT @pub_db = DB_NAME() SELECT @virtual_id = -1 SELECT @art_change = 0 select @bcp_char = 1 select @concurrent_char = 4 SELECT @f_syncstat_posted = 0 SELECT @replicate_bit = 2 /* ** Security Check. ** We use login_name stored in syssubscriptions to manage security */ /* ** Parameter Check: @publication ** Check to make sure that the publication exists, that it's not NULL, ** and that it conforms to the rules for identifiers. */ IF @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END IF @publication <> '%' BEGIN EXECUTE @retcode = dbo.sp_validname @publication IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) END IF NOT EXISTS (SELECT * FROM syspublications WHERE name LIKE @publication) BEGIN IF @publication = '%' RAISERROR (14008, 11, -1) ELSE RAISERROR (20026, 11, -1, @publication) RETURN (1) END /* ** Parameter Check: @article ** Check to make sure that the article exists, that it's not null, ** and that it conforms to the rules for identifiers. */ IF @article IS NULL BEGIN RAISERROR (14043, 16, -1, '@article') RETURN (1) END /* IF @article <> '%' BEGIN EXECUTE @retcode = dbo.sp_validname @article IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) END */ IF NOT EXISTS (SELECT * FROM sysextendedarticlesview a, syspublications b WHERE a.name LIKE @article AND a.pubid = b.pubid AND b.name LIKE @publication) BEGIN IF @article = '%' RAISERROR (14009, 11, -1, @publication) ELSE RAISERROR (20027, 11, -1, @article) RETURN (1) END /* ** Parameter Check: @subscriber ** Check to make sure that the subscriber exists, that it is not NULL, ** and that it conforms to the rules for identifiers. ** Null subscriber represents virtual subscriptions */ IF @subscriber IS NOT NULL AND @subscriber <> '%' BEGIN EXECUTE @retcode = dbo.sp_validname @subscriber IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default AND (srvstatus & 4) <> 0) BEGIN RAISERROR (14063, 11, -1) RETURN (1) END END /* ** Parameter Check: @status. ** Set the @statusid according to the @status value. Values can be ** any of the following: ** ** status statusid ** ========= ======== ** inactive 0 ** subscribed 1 ** active 2 ** initiated 3 */ IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('active', 'subscribed', 'inactive', 'initiated') BEGIN RAISERROR (14065, 16, -1) RETURN (1) END IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated') SELECT @statusid = @initiated ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('active') SELECT @statusid = @active ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed') SELECT @statusid = @subscribed ELSE SELECT @statusid = @inactive /* ** Parameter Check: @previous_status. ** Set the @prevstatid according to the @previous_status value. ** Values can be any of the following: ** ** previous_status prevstatid ** =============== ========== ** inactive 0 ** subscribed 1 ** active 2 ** initiated 3 */ IF @previous_status IS NOT NULL BEGIN IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('initiated','active', 'subscribed', 'inactive') BEGIN RAISERROR (14066, 16, -1) RETURN (1) END IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) BEGIN RAISERROR (14067, 16, -1) RETURN (1) END IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated') SELECT @prevstatid = @initiated ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('active') SELECT @prevstatid = @active ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed') SELECT @prevstatid = @subscribed ELSE SELECT @prevstatid = @inactive END /* ** Parameter Check: @destination_db. ** Set @destination_db to current database if not specified. Make ** sure that the @destination_db conforms to the rules for identifiers. */ IF @destination_db <> '%' BEGIN EXECUTE @retcode = dbo.sp_validname @destination_db IF @retcode <> 0 RETURN (1) END /* ** Get distribution server information for remote RPC ** subscription calls. ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC. */ if @ignore_distributor = 1 select @no_distproc = 1 else select @no_distproc = 0 IF @no_distproc = 0 --and @from_auto_sync = 0 BEGIN EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 BEGIN RAISERROR (14071, 16, -1) RETURN (1) END IF @retcode <> 0 OR @distribdb IS NULL OR @distributor IS NULL BEGIN RAISERROR (14071, 16, -1) RETURN (1) END END create table #sysextendedarticlesview ( artid int NULL, columns varbinary(32) NULL, creation_script nvarchar(255) collate database_default null, del_cmd nvarchar(255) collate database_default null, description nvarchar(255) collate database_default null, dest_table sysname collate database_default null, filter int NULL, filter_clause ntext NULL, ins_cmd nvarchar(255) collate database_default null, name sysname collate database_default null, objid int NULL, pubid int NULL, pre_creation_cmd tinyint NULL, status tinyint NULL, sync_objid int NULL, type tinyint NULL, upd_cmd nvarchar(255) collate database_default null, schema_option binary(8) NULL, dest_owner sysname collate database_default null ) insert into #sysextendedarticlesview select * from sysextendedarticlesview begin tran save TRANSACTION changesubstatus SELECT @finished_virtual = 0 SELECT @finished_real = 0 /* ** If @subscriber is null, don't process real subscriptions ** If @subscriber is not null and '%', don't process virtual subscriptions */ IF @subscriber IS NULL SELECT @finished_real = 1 ELSE IF @subscriber <> '%' SELECT @finished_virtual = 1 WHILE (@finished_real = 0 OR @finished_virtual = 0) BEGIN /* ** Declare cursor containing subscriptions to be updated. */ IF @finished_real = 0 BEGIN IF @previous_status IS NOT NULL BEGIN DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR SELECT sub.artid, art.objid, sub.srvid, ss.srvname, sub.dest_db, sub.status, case when ss.srvproduct = 'MSREPL-NONSQL' or pub.allow_dts = 1 then 1 else 0 end, pub.repl_freq, art.type, pub.immediate_sync, pub.enabled_for_internet, pub.allow_anonymous, sub.subscription_type, sub.sync_type, sub.update_mode, art.name, sub.login_name, sub.loopback_detection, pub.pubid FROM syssubscriptions sub, #sysextendedarticlesview art, syspublications pub, master..sysservers ss WHERE pub.name LIKE @publication collate database_default AND art.name LIKE @article collate database_default AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default)) AND sub.srvid = ss.srvid AND sub.artid = art.artid AND art.pubid = pub.pubid AND sub.status = @prevstatid AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db collate database_default)) END ELSE BEGIN DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR SELECT sub.artid, art.objid, sub.srvid, ss.srvname, sub.dest_db, sub.status, case when ss.srvproduct = 'MSREPL-NONSQL' or pub.allow_dts = 1 then 1 else 0 end, pub.repl_freq, art.type, pub.immediate_sync, pub.enabled_for_internet, pub.allow_anonymous, sub.subscription_type, sub.sync_type, sub.update_mode, art.name, sub.login_name, sub.loopback_detection, pub.pubid FROM syssubscriptions sub, #sysextendedarticlesview art, syspublications pub, master..sysservers ss WHERE pub.name LIKE @publication collate database_default AND art.name LIKE @article collate database_default AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default)) AND sub.srvid = ss.srvid AND sub.artid = art.artid AND art.pubid = pub.pubid AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db)) END SELECT @finished_real = 1 END ELSE IF @finished_virtual = 0 BEGIN DECLARE @sub_bit smallint DECLARE @null_name sysname SELECT @sub_bit = 4 SELECT @null_name = NULL /* ** Treat anonymous virtual subscription as DSN subscriber. ** This will cause sp_MSarticlecol being called in sp_changesubstatus */ DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR SELECT sub.artid, art.objid, sub.srvid, @null_name, /* subscriber name. NULL for virtual */ sub.dest_db, sub.status, case when (pub.allow_anonymous = 1 and (pub.sync_method = @bcp_char or pub.sync_method = @concurrent_char)) or pub.allow_dts = 1 then 1 else 0 end, /*indicate dsn or not */ pub.repl_freq, art.type, pub.immediate_sync, pub.enabled_for_internet, pub.allow_anonymous, sub.subscription_type, sub.sync_type, sub.update_mode, art.name, login_name, sub.loopback_detection, pub.pubid FROM syssubscriptions sub, #sysextendedarticlesview art, syspublications pub WHERE pub.name LIKE @publication AND art.name LIKE @article AND sub.srvid = -1 AND sub.artid = art.artid AND art.pubid = pub.pubid SELECT @finished_virtual = 1 END OPEN hCsubstatus FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db, @sub_status, @non_sql_flag, @repl_freq, @art_type, @immediate_sync, @enabled_for_internet, @allow_anonymous, @subscription_type, @sync_type, @update_mode, @art_name, @login_name, @loopback_detection,@pubid WHILE (@@fetch_status <> -1) BEGIN IF suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1 AND is_member ('db_owner') <> 1 BEGIN RAISERROR (14126, 11, -1) RETURN (1) END /* ** condition 1: ** If current status is same as new status, and status is not 'initiated' do nothing. ** If both old and new status = 'initiated', this indicates that the ** snapshot agent previously bombed out between the initiation and activation stages and ** is now again trying to sync the publication. ** ** condition 2: ** @auto_sync_only is used by snapshot for immediate_sync ** publications. ** ** condition 3: ** Because sp_MSactivate_auto_sub (and thus the snapshot agent) ** calls this procedure for all subscriptions, we need to ignore ** the real subscriptions that are already active so that they won't be ** transitioned to the initiated state. If we don't do this, those ** subscriptions will be resynced using the new snapshot. ** ** however, we DO want a new snapshot to be generated for virtual ** subscriptions to active publications. ** */ IF (@sub_status = @statusid AND @sub_status <> @initiated ) OR (@from_auto_sync = 1 AND @sync_type <> @automatic) OR (@sub_status = @active AND @statusid = @initiated AND @srvid <> -1 AND @from_auto_sync = 1) BEGIN FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db, @sub_status, @non_sql_flag, @repl_freq, @art_type, @immediate_sync, @enabled_for_internet, @allow_anonymous, @subscription_type, @sync_type, @update_mode, @art_name, @login_name, @loopback_detection, @pubid CONTINUE END -- If changing a virtual subscription to 'subscribed' status -- change the immediate_sync_ready bit if @statusid = @subscribed and @sub_name is NULL begin UPDATE syspublications SET immediate_sync_ready = 0 WHERE pubid = @pubid and immediate_sync_ready <> 0 IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RETURN (1) END end -- acquire schema lock, mark rollback point in order to allow -- for 'unflush' of proc cache declare @qualified_name nvarchar(512) exec dbo.sp_MSget_qualified_name @tabid, @qualified_name output exec dbo.sp_replupdateschema @qualified_name, @schemastabilityonly /* ** Update syssubscription status */ UPDATE syssubscriptions SET status = @statusid FROM syssubscriptions sub, sysextendedarticlesview art, syspublications pub WHERE pub.name LIKE @publication AND art.artid = @artid AND sub.srvid = @srvid AND sub.artid = @artid AND art.pubid = pub.pubid AND sub.dest_db = @dest_db if @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14053, 16, -1) RETURN (1) END -- -- Subscription reinitialization processing for Immediate -- and Queued publications -- if (@update_mode in (1,2,3,4,5)) begin select @retcode = 0 IF ((@statusid != @active) AND (@sub_status = @active)) begin -- -- If we are going from active state to subscribed -- set the reinit column so that no more updates from -- subscriber are applied until (re)activation -- update dbo.syssubscriptions set queued_reinit = 1 where artid = @artid and srvid = @srvid and dest_db = @dest_db end ELSE IF ((@statusid = @active) AND (@sub_status != @active )) begin -- -- If we are going from subscribed state to active state -- if (@update_mode = 1) begin -- -- Sync tran case : reset the reinit column -- update dbo.syssubscriptions set queued_reinit = 0 where artid = @artid and srvid = @srvid and dest_db = @dest_db end -- -- For queued case : we do not need to send compensating -- command anymore, sp_addqueued_artinfo will do the -- queue reinitialization for all types of queued -- subscriptions -- end -- -- Check for error -- if (@@error != 0 or @retcode != 0) begin CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14053, 16, -1) RETURN (1) end end /* ** Get timestamp of subscription. */ EXEC @retcode = dbo.sp_replincrementlsn_internal @xact_seqno OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RETURN (1) END select @sub_ts = @xact_seqno IF @sub_ts IS NULL BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14053, 16, -1) RETURN (1) END ------------------------------------------------------------------- -- If initiating the subscription, toss a SYNCINIT token into the -- log for the article and return LSN as a results set -- -- Note: This should come after the subscription LSN is obtained. -- in order to assure proper application of SYNSTAT tokens in the -- distribution database ------------------------------------------------------------------- IF @statusid = @initiated --and @sub_status <> @initiated BEGIN -- set filtered status. Must log old text information during initiated state -- in order to support update splitting exec sp_MSsetfilteredstatus @tabid -- set nonsqlsub status. must prevent UPDATETEXT operations during -- initiated state exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'add' exec sp_replpostsyncstatus @pubid, @artid, 1, @syncinit_lsn output if @f_syncstat_posted = 0 begin select @pubid, @artid, @syncinit_lsn select @f_syncstat_posted = 1 end END ------------------------------------------------------------------- -- If changing the state FROM initiated, post a SYNCDONE token to the -- log for the article. ------------------------------------------------------------------- IF @sub_status = @initiated and @statusid <> @initiated BEGIN -- reset filtered status to normal value exec sp_MSsetfilteredstatus @tabid -- clear nonsqlsub status for this article. exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'drop' --if @f_syncstat_posted = 0 --begin exec sp_replpostsyncstatus @pubid, @artid, 0, @syncinit_lsn output -- select @f_syncstat_posted = 1 --end END /* ** If activating subscription, update sysextendedarticlesview, sysobjects and ** MSrepl_subscriptions. */ IF @statusid in ( @active, @initiated ) BEGIN /* ** Update status of article to show it has been activated. */ IF @repl_freq = 0 and EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid AND status & 1 <> 1) BEGIN -- At most one row will be updated in the following two updates as the artid is unique -- among both sysarticles and sysschemaarticles UPDATE sysarticles SET status = status | 1 WHERE artid = @artid IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14069, 16, -1) RETURN (1) END UPDATE sysschemaarticles SET status = status | 1 WHERE artid = @artid IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14069, 16, -1) RETURN (1) END SELECT @art_change = 1 END /* ** Turn the replication flag on for this object in the ** sysobjects table (make it logbased). */ if @repl_freq = 0 BEGIN UPDATE sysobjects SET replinfo = replinfo | @replicate_bit WHERE id = ( SELECT objid FROM sysextendedarticlesview WHERE artid = @artid ) END IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14068, 16, -1) RETURN (1) END END /* ** Update status of all columns if subscriber is non-SQL Server. */ IF @non_sql_flag <> 0 AND ( @art_type & 1 ) = 1 BEGIN IF @statusid = @subscribed OR @statusid = @active BEGIN EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL, 'nonsqlsub', 'add' IF @@ERROR <> 0 OR @retcode <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14068, 16, -1) RETURN (1) END END ELSE IF @statusid = @inactive BEGIN EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL, 'nonsqlsub', 'drop' IF @@ERROR <> 0 OR @retcode <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14068, 16, -1) RETURN (1) END END END /* ** If deactivating subscription, update sysextendedarticlesview, sysobjects and ** MSrepl_subscriptions. */ IF @statusid NOT IN( @active, @initiated ) AND @sub_status IN ( @active, @initiated ) BEGIN /* ** Set the article status to 'inactive' if there are ** no other active subscriptions on it. */ IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE artid = @artid AND status = @active) BEGIN IF EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid AND status & 1 = 1) BEGIN -- At most one row will be updated in the following two updates as the artid is unique -- among both sysarticles and sysschemaarticles UPDATE sysarticles SET status = status & ~1 WHERE artid = @artid IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14069, 16, -1) RETURN (1) END UPDATE sysschemaarticles SET status = status & ~1 WHERE artid = @artid IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RAISERROR (14069, 16, -1) RETURN (1) END SELECT @art_change = 1 END END /* ** Set the object replication bits to 'inactive' if ** there are no other active subscriptions on the ** table. */ IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE artid IN (SELECT sa.artid FROM sysextendedarticlesview sa, syspublications sp WHERE sa.objid = @tabid and sa.pubid = sp.pubid and sp.repl_freq = 0) AND status = @active) BEGIN UPDATE sysobjects SET replinfo = replinfo & ~@replicate_bit WHERE id = (SELECT objid FROM sysextendedarticlesview WHERE artid = @artid ) IF @@ERROR <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus RAISERROR (14068, 16, -1) if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RETURN (1) END END END -- Note: Not only do we need to have the replupdateschema already executed -- so we can handle rollbacks, we also need to -- acquire the schema lock before RPC to the distributor to avoid livelock -- with snapshot agents. Snapshot agents acquire lock on user table before -- updating the distribution db. if @no_distproc = 0 begin /* ** Add the active subscription to the distributor's ** subscriptions table if changing status from @inactive */ IF @sub_status = @inactive -- From inactive to subscribed or active BEGIN DECLARE @null_char sysname SELECT @null_char = NULL DECLARE @zero_bit bit SELECT @zero_bit = 0 SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadd_subscription' EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, @artid, @dest_db, @statusid, @sub_ts, @publication, @null_char, /* Pass null to @article, we already gave @artid */ @subscription_type, --@immediate_sync, @sync_type, @zero_bit, @frequency_type, @frequency_interval, @frequency_relative_interval, @frequency_recurrence_factor, @frequency_subday, @frequency_subday_interval, @active_start_time_of_day, @active_end_time_of_day, @active_start_date, @active_end_date, @optional_command_line = @optional_command_line, -- synctran @update_mode = @update_mode, @loopback_detection = @loopback_detection, @distribution_jobid = @distribution_jobid OUTPUT, @offloadagent = @offloadagent, @offloadserver = @offloadserver, @dts_package_name = @dts_package_name, @dts_package_password = @dts_package_password, @dts_package_location = @dts_package_location, @distribution_job_name = @distribution_job_name IF @@ERROR <> 0 OR @retcode <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus RAISERROR (14070, 16, -1) if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RETURN (1) END END ELSE -- From subscribed or active to others BEGIN /* ** Drop the deactivated subscription from the distributor's ** subscriptions table. */ IF @statusid = @inactive -- From subscribed to inactive or from active to inactive BEGIN SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_subscription' EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, @artid, @dest_db, @publication IF @@ERROR <> 0 OR @retcode <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus RAISERROR (14070, 16, -1) if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RETURN (1) END END ELSE -- From subscribed to initiated to active or from active to subscribed. BEGIN -- Don't do it if activating the subscription for snapshot agent. --IF NOT (@from_auto_sync = 1 AND @statusid in(@active, @initiated) ) IF NOT (@from_auto_sync = 1 AND @statusid in(@active) ) BEGIN SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSupdate_subscription' EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, @artid, @statusid, @sub_ts, @dest_db IF @@ERROR <> 0 OR @retcode <> 0 BEGIN CLOSE hCsubstatus DEALLOCATE hCsubstatus RAISERROR (14070, 16, -1) if @@trancount > 0 begin ROLLBACK TRANSACTION changesubstatus commit tran end RETURN (1) END END END END end /* ** Set internal object replication bit to 'inactive' if ** there are no other active subscriptions on the ** table. */ IF @statusid = @inactive AND @sub_status IN (@active,@initiated) AND NOT EXISTS (SELECT * FROM syssubscriptions WHERE artid IN (SELECT artid FROM sysextendedarticlesview WHERE objid = @tabid) AND status IN (@active,@initiated) ) BEGIN /* ** If it's a procedure execution article, clear proc status bits */ IF (@art_type & 8 ) = 8 BEGIN UPDATE sysobjects SET replinfo = replinfo & ~24 WHERE id = @tabid END END /* Turn on object replication */ ELSE IF @statusid = @active BEGIN IF (@art_type & 24 ) = 24 BEGIN UPDATE sysobjects SET replinfo = replinfo | 24 WHERE id = @tabid END ELSE IF( @art_type & 8 ) = 8 BEGIN UPDATE sysobjects SET replinfo = replinfo | 8 WHERE id = @tabid END END exec dbo.sp_MSget_qualified_name @tabid, @qualified_name output exec dbo.sp_replupdateschema @qualified_name, @schemastabilityonly /* ** Get next row. */ FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db, @sub_status, @non_sql_flag, @repl_freq, @art_type , @immediate_sync, @enabled_for_internet, @allow_anonymous, @subscription_type, @sync_type, @update_mode, @art_name, @login_name, @loopback_detection, @pubid END -- end while for cursor CLOSE hCsubstatus DEALLOCATE hCsubstatus END -- end while for virtual and real -- force refresh of article cache -- Only do it if necessary -- No need on brute force cleanup IF ( @art_change = 1 ) and ( @ignore_distributor = 0 ) EXECUTE dbo.sp_replflush COMMIT TRANSACTION drop table #sysextendedarticlesview RETURN(0) go EXEC dbo.sp_MS_marksystemobject sp_changesubstatus GO grant execute on dbo.sp_changesubstatus to public go -------------------------------------------------------------------------------- --. System objects (rladmin.sql) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --. sp_MSremove_userscript -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSremove_userscript') drop procedure sp_MSremove_userscript go create procedure sp_MSremove_userscript( @pubid uniqueidentifier, @drop_publication bit = 0 )as declare @retention int declare @last_snapshot datetime declare @post_snapshot_ver int declare @post_snapshot_type int declare @user_script_type int declare @retcode int declare @len int declare @file_path nvarchar(4000) declare @delfile_cmd nvarchar(4000) declare @rmdir_cmd nvarchar(4000) select @post_snapshot_type=52 select @user_script_type=46 if not exists (select * from sysmergeschemachange where pubid=@pubid and schematype=@user_script_type) return (0) select @retention=retention from sysmergepublications where pubid=@pubid select @last_snapshot=last_validated from sysmergesubscriptions where pubid=@pubid and subid=@pubid --I do not want to remove script files by setting retention to 0 if (@retention=0 or dateadd(day, -@retention, getdate()) < @last_snapshot) and @drop_publication = 0 return (0) select @post_snapshot_ver=schemaversion from sysmergeschemachange where schematype=@post_snapshot_type and pubid=@pubid --only get those script that can be safely removed declare #per_script cursor local fast_forward for select schematext from sysmergeschemachange where pubid=@pubid and schematype=@user_script_type and (schemaversion<@post_snapshot_ver or @drop_publication = 1) open #per_script fetch #per_script into @file_path while (@@fetch_status<>-1) begin if(left(@file_path, 1) = N'0' or left(@file_path, 1) = N'1') select @file_path = right(@file_path, len(@file_path) - 1) select @delfile_cmd = N'del "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"' EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT if @@ERROR<>0 goto FAILURE select @len=CHARINDEX ( '\' , reverse(@file_path) ) select @file_path=SUBSTRING(@file_path , 1 , len(@file_path)-@len + 1) select @delfile_cmd = N'rmdir "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"' EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT if @@ERROR<>0 goto FAILURE fetch next from #per_script into @file_path end close #per_script deallocate #per_script return (0) FAILURE: close #per_script deallocate #per_script return (1) go EXEC dbo.sp_MS_marksystemobject 'sp_MSremove_userscript' go -------------------------------------------------------------------------------- --. sp_MScomputemergearticlescreationorder -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MScomputemergearticlescreationorder') drop procedure sp_MScomputemergearticlescreationorder go raiserror(15339,-1,-1,'sp_MScomputemergearticlescreationorder') GO CREATE PROCEDURE sp_MScomputemergearticlescreationorder @publication sysname AS SET NOCOUNT ON DECLARE @pubid uniqueidentifier DECLARE @max_level int DECLARE @current_level int DECLARE @update_level int DECLARE @limit int DECLARE @retcode int SELECT @retcode = 0 EXEC @retcode = sp_MSreplcheck_publish IF @@ERROR <> 0 OR @retcode <> 0 return (1) SELECT @pubid = NULL -- Get the pubid from sysmergepublications SELECT @pubid = pubid FROM sysmergepublications WHERE name = @publication AND UPPER(publisher) = UPPER(@@SERVERNAME) AND publisher_db = DB_NAME() IF @@ERROR <> 0 RETURN (1) IF @pubid IS NULL BEGIN RAISERROR(20026, 16, -1, @publication) RETURN (1) END -- Find out the total number of articles in this publication and -- compute the maximum tree height based on the number of articles in -- the publication. Here, the tree height is counted from the -- leaf-nodes towards the root(s) starting from @max_level SELECT @max_level = COUNT(*) + 10, @limit = 2 * COUNT(*) + 11 FROM sysmergeextendedarticlesview WHERE pubid = @pubid IF @@ERROR <> 0 BEGIN RETURN (1) END -- The following temp table contains the minimal amount of -- article information that we want to keep around and the current -- computed tree level of the article CREATE TABLE #article_level_info ( article sysname collate database_default not null, source_objid INT NOT NULL, tree_level INT NOT NULL, nickname INT NOT NULL, major_type TINYINT NOT NULL -- 1-view&func, 0-other ) CREATE CLUSTERED INDEX ucarticle_level_info ON #article_level_info(source_objid) IF @@ERROR <> 0 BEGIN GOTO Failure END -- Populate the article level info table. All articles will be -- assigned 0 as their initial tree level. Having -- a tree level of 0 means that the algorithm hasn't discovered -- any objects that the article depends on within the publication. INSERT INTO #article_level_info SELECT name, objid, 0, ISNULL(nickname, 5*@max_level), CASE type WHEN 0x40 THEN 1 WHEN 0x80 THEN 1 ELSE 0 END FROM sysmergeextendedarticlesview WHERE pubid = @pubid -- To jump-start the algorithm, update the tree_level of -- all articles with no dependency to @max_level. UPDATE #article_level_info SET tree_level = @max_level WHERE NOT EXISTS (SELECT * FROM sysdepends WHERE source_objid = id AND id <> depid) IF @@ERROR <> 0 GOTO Failure -- For each increasing tree level starting from @max_level, update the -- the tree_level of articles depending on objects at the current -- level to current level + 1 SELECT @current_level = @max_level WHILE 1 = 1 BEGIN SELECT @update_level = @current_level + 1 UPDATE #article_level_info SET tree_level = @update_level FROM #article_level_info INNER JOIN sysdepends d ON #article_level_info.source_objid = d.id INNER JOIN #article_level_info ali1 ON (d.depid = ali1.source_objid AND ali1.tree_level = @current_level AND d.id <> d.depid) -- Terminate the algorithm if we cannot find any articles -- depending on articles at the current level IF @@ROWCOUNT = 0 GOTO PHASE1 IF @@ERROR <> 0 GOTO Failure SELECT @current_level = @current_level + 1 -- Although there should not be any circular -- dependencies among the articles, the following -- check is performed to guarantee that -- the algorithm will terminate even if there -- is circular dependency among the articles -- Note that with at least one node per level, -- the current level can never exceed the total -- number of articles (nodes) unless there is -- circular dependency among the articles. -- @limit is defined to be # of articles + 1 -- although @limit = # of articles - 1 will be -- sufficient. This is to make absolutely sure that -- the algorithm will never terminate too early IF @current_level > @limit GOTO PHASE1 END PHASE1: -- There may be interdependencies among articles -- that haven't been included in the previous calculations so -- we compute the proper order among these articles here. SELECT @limit = @max_level - 9 SELECT @current_level = 0 WHILE 1 = 1 BEGIN SELECT @update_level = @current_level + 1 UPDATE #article_level_info SET tree_level = @update_level FROM #article_level_info INNER JOIN sysdepends d ON (#article_level_info.source_objid = d.id AND #article_level_info.tree_level < @max_level) INNER JOIN #article_level_info ali1 ON (d.depid = ali1.source_objid AND ali1.tree_level = @current_level AND d.id <> d.depid) IF @@ROWCOUNT = 0 GOTO PHASE2 IF @@ERROR <> 0 GOTO Failure SELECT @current_level = @current_level + 1 IF @current_level > @limit GOTO PHASE2 END PHASE2: -- Select the articles out of #article_level_info -- in ascending order of tree_level. This will give -- the proper order in which articles can be created -- without violating the internal dependencies among -- the themselves. Note that this algorithm still allows -- unresolved external references outside the publication. -- All this algorithm can guarantee is that all articles will -- be created successfully using the resulting order if -- there is no dependent object outside the publication. SELECT article FROM #article_level_info ORDER BY major_type ASC, tree_level ASC, nickname ASC DROP TABLE #article_level_info RETURN (0) Failure: DROP TABLE #article_level_info RETURN (1) GO exec dbo.sp_MS_marksystemobject sp_MScomputemergearticlescreationorder go grant exec on dbo.sp_MScomputemergearticlescreationorder to public go -------------------------------------------------------------------------------- --. System objects (rlrecon.sql) -------------------------------------------------------------------------------- if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumschemachange_80') drop procedure sp_MSenumschemachange_80 raiserror('Creating procedure sp_MSenumschemachange_80', 0,1) GO CREATE PROCEDURE sp_MSenumschemachange_80( @pubid uniqueidentifier, @AlterTableOnly int, @schemaversion int ) as set nocount on /* ** To public */ declare @alter_table_type int declare @reinit_all_type int declare @reinit_all_upload_type int declare @schemaversion_of_snapshottrailer int select @reinit_all_type = 12 select @alter_table_type = 11 select @reinit_all_upload_type = 14 if (@schemaversion is null) begin RAISERROR(14043, 16, -1, '@schemaversion') return (1) end -- @schema_needed = 0 - only send back reinitall command, if any -- @schema_needed = 1 - normal enumeration -- @schema_needed = 2 - only send back alter-table command, if any -- @schema_needed = 3 - only send back reinitall-with-upload command, if any. if (@AlterTableOnly = 1) begin select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where pubid=@pubid and schemaversion > @schemaversion and schematype = @alter_table_type return (0) end if exists (select * from sysmergeschemachange where pubid=@pubid and ((schemaversion > @schemaversion and schematype = @reinit_all_type) or (schemaversion > @schemaversion and schematype = @reinit_all_upload_type))) begin select @schemaversion=0 end -- If subscriber missed a preparecleanup and a completecleanup they must be reinitialized if exists (select * from sysmergeschemachange where pubid=@pubid and schemaversion > @schemaversion and schematype = 17) and exists (select * from sysmergeschemachange where pubid=@pubid and schemaversion > @schemaversion and schematype = 19) begin set @schemaversion=0 end if (@schemaversion > 0) begin -- Subscriber has already received the snapshot so filter out -- the pre/post-snapshot commands. -- Also filter out the schemtypes for the setlastsentgen (5) and setlastrecgen (6) -- This ensures that the subscriber does not apply these schema changes when -- it applies incremental schema - ie the perf optimization that is implemented -- by setting last sent/rec generation should be done only for brand new subscriptions. select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6) order by schemaversion end Else begin -- Subscriber requires a snapshot, so carefully sequence the -- pre/post-snapshot commands around the snapshot boundary create table #schemachanges ( pubid uniqueidentifier NOT NULL, artid uniqueidentifier NULL, schemaversion int NOT NULL, schemaguid uniqueidentifier NOT NULL, schematype int NOT NULL, schematext nvarchar(2000) collate database_default not null, seqno int identity NOT NULL ) truncate table #schemachanges -- Insert snapshot header -- Header begins insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype = 50 -- Header content insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype in (25, 53, 54, 55, 56, 57, 58) order by schemaversion -- Header ends insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype = 51 -- End of snapshot header -- Insert pre command insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype = 40 -- Exclude pre-post, but include snapshot only commands insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype in (2, 3, 4, 20, 7, 60, 61, 62, 63, 64) order by schemaversion -- Dynamic BCP commands insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype in (131, 132) order by schemaversion -- DRI/Trg/XPROP insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype in (10, 15, 65) order by schemaversion -- Insert post command insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype = 45 -- Insert snapshot trailer insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype = 52 -- Insert other schema changes insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and schematype not in (2, 3, 4, 10, 15, 20, 7, 40, 45, 60) and schematype not in (61, 62, 63, 64, 65) and schematype not in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58) and schematype not in (131, 132) -- dynamic bcp commands and schematype not in (46, 11, 13) -- The on-demand script and schema replication commands should not be enumerated unless -- we have made sure that it was posted after the current snapshot. and pubid = @pubid order by schemaversion -- get the schemaversion of the snapshot trailer row select @schemaversion_of_snapshottrailer = schemaversion from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid and schematype = 52 if (@schemaversion_of_snapshottrailer is not null) begin -- insert schema changes for on-demand script and schema replication commands which have schemaversion greater than -- schemaversion of the snapshot trailer row insert into #schemachanges select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion_of_snapshottrailer and schematype in (46, 11, 13) -- The on-demand script and schema replication commands only. and pubid = @pubid order by schemaversion end declare @endofsnapshot int select @endofsnapshot = min(seqno) from #schemachanges where schematype = 52 delete #schemachanges where seqno > @endofsnapshot and (schematype in (2, 3, 4, 10, 15, 20, 7, 40, 45, 65) or schematype in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58)) --only list the last reinitall command delete schemachanges1 from #schemachanges schemachanges1,#schemachanges schemachanges2 where schemachanges1.pubid=@pubid and schemachanges1.schematype=12 and schemachanges2.pubid=@pubid and schemachanges2.schematype=12 and schemachanges1.schemaversion<schemachanges2.schemaversion --only list the last reinitall-with-upload command delete schemachanges1 from #schemachanges schemachanges1, #schemachanges schemachanges2 where schemachanges1.pubid=@pubid and schemachanges1.schematype=14 and schemachanges2.pubid=@pubid and schemachanges2.schematype=14 and schemachanges1.schemaversion<schemachanges2.schemaversion select pubid, artid, schemaversion, schemaguid, schematype, schematext from #schemachanges order by seqno drop table #schemachanges end return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumschemachange_80 go grant exec on dbo.sp_MSenumschemachange_80 to public go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSregistersubscription') drop procedure sp_MSregistersubscription go raiserror('Creating procedure sp_MSregistersubscription', 0,1) go CREATE PROCEDURE sp_MSregistersubscription ( @replication_type int, /* Transactional = 1, Merge = 2 */ @publisher sysname, @publisher_db sysname, @publisher_security_mode int = NULL, /* 0 standard; 1 integrated */ @publisher_login sysname = NULL, @publisher_password nvarchar(524) = NULL, @publication sysname, @subscriber sysname, @subscriber_db sysname, @subscriber_security_mode int = NULL, /* 0 standard; 1 integrated */ @subscriber_login sysname = NULL, @subscriber_password nvarchar(524) = NULL, @distributor sysname, @distributor_security_mode int = NULL, @distributor_login sysname = NULL, @distributor_password nvarchar(524) = NULL, @subscription_id uniqueidentifier , @independent_agent int = NULL, @subscription_type int, @use_interactive_resolver int = NULL, @failover_mode int = NULL ) AS SET NOCOUNT ON /* MobileSync Support */ declare @subscription_name nvarchar(1000) declare @regkey nvarchar(1000) declare @subidstr nvarchar(38) declare @profile_name nvarchar(100) declare @retcode int set @subscription_name = @publisher + ':' + @publisher_db + ':' + @publication + ':' + @subscriber + ':' + @subscriber_db /* Replace back slash with forward slash so that the key name is a valid REGISTRY key name */ set @subscription_name = REPLACE(@subscription_name,'\','/') set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name set @subidstr = '{' + convert ( nchar(36), @subscription_id) + '}' set @profile_name = formatmessage(20550) -- SyncMgr Profile EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'ProfileName', 'REG_SZ', @profile_name if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'ReplicationType', 'REG_DWORD', @replication_type if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'SubscriptionType', 'REG_DWORD', @subscription_type if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'Subid', 'REG_SZ', @subidstr if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'Publisher', 'REG_SZ', @publisher if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'PublisherDb', 'REG_SZ', @publisher_db if @retcode <> 0 OR @@ERROR <> 0 return 1 IF @use_interactive_resolver IS NOT NULL BEGIN EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'UseInteractiveResolver', 'REG_DWORD', @use_interactive_resolver if @retcode <> 0 OR @@ERROR <> 0 return 1 END /* If Publisher security mode is NOT NULL, write out the entries */ if @publisher_security_mode IS NOT NULL begin EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'PublisherSecurityMode', 'REG_DWORD', @publisher_security_mode if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'PublisherLogin', 'REG_SZ', @publisher_login if @retcode <> 0 OR @@ERROR <> 0 return 1 end EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'Publication', 'REG_SZ', @publication if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'Subscriber', 'REG_SZ', @subscriber if @retcode <> 0 OR @@ERROR <> 0 return 1 /* If Subscriber security mode is NOT NULL, write out the entries */ if @subscriber_security_mode IS NOT NULL begin EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'SubscriberSecurityMode', 'REG_DWORD', @subscriber_security_mode if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'SubscriberLogin', 'REG_SZ', @subscriber_login if @retcode <> 0 OR @@ERROR <> 0 return 1 end EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'SubscriberDb', 'REG_SZ', @subscriber_db if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'Distributor', 'REG_SZ', @distributor if @retcode <> 0 OR @@ERROR <> 0 return 1 /* If Distributor security mode is NOT NULL, write out the entries */ if @distributor_security_mode IS NOT NULL begin EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'DistributorSecurityMode', 'REG_DWORD', @distributor_security_mode if @retcode <> 0 OR @@ERROR <> 0 return 1 EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'DistributorLogin', 'REG_SZ', @distributor_login if @retcode <> 0 OR @@ERROR <> 0 return 1 end if @independent_agent IS NOT NULL begin EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'IndependentAgent', 'REG_DWORD', @independent_agent if @retcode <> 0 OR @@ERROR <> 0 return 1 end IF @failover_mode IS NOT NULL begin EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @regkey, 'FailoverMode', 'REG_DWORD', @failover_mode if @retcode <> 0 OR @@ERROR <> 0 return 1 end -- Mark enabled_for_syncmgr bit if every thing succeeded. -- If the row exists in MSreplication_properties table, -- set enabled_for_syncmgr bit -- The logic need to be here because UI call this sp directly. if exists (select * from sysobjects where name = 'MSsubscription_properties') begin update MSsubscription_properties set enabled_for_syncmgr = 1 where UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisher_db and publication = @publication if @retcode <> 0 OR @@ERROR <> 0 return 1 end return 0 GO exec sp_MS_upd_sysobj_category 2 go exec sp_configure 'allow updates',0 go reconfigure with override go